Skip to content
2 changes: 2 additions & 0 deletions src/graphon/dsl/entities.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

from abc import abstractmethod
from collections.abc import Mapping
from enum import StrEnum, auto
from typing import Any, Protocol
Expand Down Expand Up @@ -125,4 +126,5 @@ def loadable(self) -> bool:


class TypedNodeFactory(Protocol):
@abstractmethod
def create_node(self, node_config: NodeConfigDict) -> Any: ...
9 changes: 9 additions & 0 deletions src/graphon/file/protocols.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

from abc import abstractmethod
from collections.abc import Generator
from typing import TYPE_CHECKING, Literal, Protocol

Expand All @@ -18,26 +19,32 @@ class WorkflowFileRuntimeProtocol(Protocol):
"""

@property
@abstractmethod
def multimodal_send_format(self) -> str: ...

@abstractmethod
def http_get(
self,
url: str,
*,
follow_redirects: bool = True,
) -> HttpResponseProtocol: ...

@abstractmethod
def storage_load(self, path: str, *, stream: bool = False) -> bytes | Generator: ...

@abstractmethod
def load_file_bytes(self, *, file: File) -> bytes: ...

@abstractmethod
def resolve_file_url(
self,
*,
file: File,
for_external: bool = True,
) -> str | None: ...

@abstractmethod
def resolve_upload_file_url(
self,
*,
Expand All @@ -46,6 +53,7 @@ def resolve_upload_file_url(
for_external: bool = True,
) -> str: ...

@abstractmethod
def resolve_tool_file_url(
self,
*,
Expand All @@ -54,6 +62,7 @@ def resolve_tool_file_url(
for_external: bool = True,
) -> str: ...

@abstractmethod
def verify_preview_signature(
self,
*,
Expand Down
2 changes: 2 additions & 0 deletions src/graphon/graph/graph.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import logging
from abc import abstractmethod
from collections import defaultdict
from collections.abc import Mapping, Sequence
from typing import Any, Protocol, final
Expand All @@ -27,6 +28,7 @@ class NodeFactory(Protocol):
allowing for different node creation strategies while maintaining type safety.
"""

@abstractmethod
def create_node(self, node_config: NodeConfigDict) -> Node:
"""Create a Node instance from node configuration data.

Expand Down
2 changes: 2 additions & 0 deletions src/graphon/graph/validation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

from abc import abstractmethod
from collections.abc import Sequence
from dataclasses import dataclass
from typing import TYPE_CHECKING, Protocol
Expand Down Expand Up @@ -34,6 +35,7 @@ def __init__(self, issues: Sequence[GraphValidationIssue]) -> None:
class GraphValidationRule(Protocol):
"""Protocol that individual validation rules must satisfy."""

@abstractmethod
def validate(self, graph: Graph) -> Sequence[GraphValidationIssue]:
"""Validate the provided graph and return any discovered issues."""
...
Expand Down
3 changes: 3 additions & 0 deletions src/graphon/graph_engine/command_channels/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
to/from a GraphEngine instance, supporting both local and distributed scenarios.
"""

from abc import abstractmethod
from typing import Protocol

from ..entities.commands import GraphEngineCommand
Expand All @@ -16,6 +17,7 @@ class CommandChannel(Protocol):
this channel is dedicated to that single execution.
"""

@abstractmethod
def fetch_commands(self) -> list[GraphEngineCommand]:
"""Fetch pending commands for this GraphEngine instance.

Expand All @@ -27,6 +29,7 @@ def fetch_commands(self) -> list[GraphEngineCommand]:
"""
...

@abstractmethod
def send_command(self, command: GraphEngineCommand) -> None:
"""Send a command to be processed by this GraphEngine instance.

Expand Down
15 changes: 15 additions & 0 deletions src/graphon/graph_engine/command_channels/redis_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""

import json
from abc import abstractmethod
from contextlib import AbstractContextManager
from typing import Any, Protocol, final

Expand All @@ -27,18 +28,32 @@
class RedisPipelineProtocol(Protocol):
"""Minimal Redis pipeline contract used by the command channel."""

@abstractmethod
def lrange(self, name: str, start: int, end: int) -> Any: ...

@abstractmethod
def delete(self, *names: str) -> Any: ...

@abstractmethod
def execute(self) -> list[Any]: ...

@abstractmethod
def rpush(self, name: str, *values: str) -> Any: ...

@abstractmethod
def expire(self, name: str, time: int) -> Any: ...

@abstractmethod
def set(self, name: str, value: str, ex: int | None = None) -> Any: ...

@abstractmethod
def get(self, name: str) -> Any: ...


class RedisClientProtocol(Protocol):
"""Redis client contract required by the command channel."""

@abstractmethod
def pipeline(self) -> AbstractContextManager[RedisPipelineProtocol]: ...


Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Main command processor for handling external commands."""

import logging
from abc import abstractmethod
from collections.abc import Callable
from typing import Protocol, final

Expand All @@ -15,6 +16,7 @@
class CommandHandler[CommandT: GraphEngineCommand](Protocol):
"""Protocol for command handlers."""

@abstractmethod
def handle(
self,
command: CommandT,
Expand Down
4 changes: 0 additions & 4 deletions src/graphon/graph_engine/domain/graph_execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

from graphon.entities.pause_reason import PauseReason
from graphon.enums import NodeState
from graphon.runtime.graph_runtime_state import GraphExecutionProtocol

from .node_execution import NodeExecution

Expand Down Expand Up @@ -246,6 +245,3 @@ def loads(self, data: str) -> None:
def record_node_failure(self) -> None:
"""Increment the count of node failures encountered during execution."""
self.exceptions_count += 1


_: GraphExecutionProtocol = GraphExecution(workflow_id="")
8 changes: 8 additions & 0 deletions src/graphon/graph_engine/ready_queue/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
for execution, supporting both in-memory and persistent storage scenarios.
"""

from abc import abstractmethod
from collections.abc import Sequence
from typing import Protocol

Expand Down Expand Up @@ -35,6 +36,7 @@ class ReadyQueue(Protocol):
that can be serialized for state storage.
"""

@abstractmethod
def put(self, item: str) -> None:
"""Add a node ID to the ready queue.

Expand All @@ -44,6 +46,7 @@ def put(self, item: str) -> None:
"""
...

@abstractmethod
def get(self, timeout: float | None = None) -> str:
"""Retrieve and remove a node ID from the queue.

Expand All @@ -56,6 +59,7 @@ def get(self, timeout: float | None = None) -> str:
"""
...

@abstractmethod
def task_done(self) -> None:
"""Indicate that a previously retrieved task is complete.

Expand All @@ -64,6 +68,7 @@ def task_done(self) -> None:
"""
...

@abstractmethod
def empty(self) -> bool:
"""Check if the queue is empty.

Expand All @@ -73,6 +78,7 @@ def empty(self) -> bool:
"""
...

@abstractmethod
def qsize(self) -> int:
"""Get the approximate size of the queue.

Expand All @@ -82,6 +88,7 @@ def qsize(self) -> int:
"""
...

@abstractmethod
def dumps(self) -> str:
"""Serialize the queue state to a JSON string for storage.

Expand All @@ -92,6 +99,7 @@ def dumps(self) -> str:
"""
...

@abstractmethod
def loads(self, data: str) -> None:
"""Restore the queue state from a JSON string.

Expand Down
15 changes: 15 additions & 0 deletions src/graphon/http/protocols.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from abc import abstractmethod
from collections.abc import Mapping
from typing import Any, Protocol

Expand All @@ -6,45 +7,59 @@

class HttpResponseProtocol(Protocol):
@property
@abstractmethod
def headers(self) -> Mapping[str, str]: ...

@property
@abstractmethod
def content(self) -> bytes: ...

@property
@abstractmethod
def status_code(self) -> int: ...

@property
@abstractmethod
def text(self) -> str: ...

@property
@abstractmethod
def is_success(self) -> bool: ...

@abstractmethod
def raise_for_status(self) -> None: ...


class HttpClientProtocol(Protocol):
@property
@abstractmethod
def max_retries_exceeded_error(self) -> type[Exception]: ...

@property
@abstractmethod
def request_error(self) -> type[Exception]: ...

@abstractmethod
def get(self, url: str, max_retries: int = ..., **kwargs: Any) -> HttpResponse: ...

@abstractmethod
def head(self, url: str, max_retries: int = ..., **kwargs: Any) -> HttpResponse: ...

@abstractmethod
def post(self, url: str, max_retries: int = ..., **kwargs: Any) -> HttpResponse: ...

@abstractmethod
def put(self, url: str, max_retries: int = ..., **kwargs: Any) -> HttpResponse: ...

@abstractmethod
def delete(
self,
url: str,
max_retries: int = ...,
**kwargs: Any,
) -> HttpResponse: ...

@abstractmethod
def patch(
self,
url: str,
Expand Down
2 changes: 2 additions & 0 deletions src/graphon/model_runtime/memory/prompt_message_memory.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

from abc import abstractmethod
from collections.abc import Sequence
from typing import Protocol

Expand All @@ -11,6 +12,7 @@
class PromptMessageMemory(Protocol):
"""Port for loading memory as prompt messages."""

@abstractmethod
def get_history_prompt_messages(
self,
max_token_limit: int = DEFAULT_MEMORY_MAX_TOKEN_LIMIT,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from abc import abstractmethod
from collections.abc import Sequence
from pathlib import Path
from threading import Lock
Expand All @@ -8,6 +9,7 @@


class _TokenizerProtocol(Protocol):
@abstractmethod
def encode(self, text: str) -> Sequence[int]: ...


Expand Down
4 changes: 4 additions & 0 deletions src/graphon/model_runtime/protocols/llm_runtime.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

from abc import abstractmethod
from collections.abc import Generator, Sequence
from typing import Any, Literal, Protocol, overload, runtime_checkable

Expand Down Expand Up @@ -49,6 +50,7 @@ def invoke_llm(
stream: Literal[True],
) -> Generator[LLMResultChunk, None, None]: ...

@abstractmethod
def invoke_llm(
self,
*,
Expand Down Expand Up @@ -90,6 +92,7 @@ def invoke_llm_with_structured_output(
stream: Literal[True],
) -> Generator[LLMResultChunkWithStructuredOutput, None, None]: ...

@abstractmethod
def invoke_llm_with_structured_output(
self,
*,
Expand All @@ -106,6 +109,7 @@ def invoke_llm_with_structured_output(
| Generator[LLMResultChunkWithStructuredOutput, None, None]
): ...

@abstractmethod
def get_llm_num_tokens(
self,
*,
Expand Down
2 changes: 2 additions & 0 deletions src/graphon/model_runtime/protocols/moderation_runtime.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

from abc import abstractmethod
from typing import Any, Protocol, runtime_checkable

from graphon.model_runtime.protocols.provider_runtime import ModelProviderRuntime
Expand All @@ -9,6 +10,7 @@
class ModerationModelRuntime(ModelProviderRuntime, Protocol):
"""Runtime surface required by moderation model wrappers."""

@abstractmethod
def invoke_moderation(
self,
*,
Expand Down
Loading
Loading