Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions components/src/dynamo/common/configuration/arg_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,24 @@ class ArgGroup(ABC):
Base interface for configuration groups.

Each ArgGroup represents a domain of configuration parameters with clear ownership.

Examples:
>>> import argparse
>>> from dynamo.common.configuration.arg_group import ArgGroup
>>> from dynamo.common.configuration.utils import add_argument
>>>
>>> class MyArgGroup(ArgGroup):
... def add_arguments(self, parser) -> None:
... add_argument(
... parser,
... flag_name="--my-option",
... env_var="DYN_MY_OPTION",
... default="value",
... help="A custom option.",
... )
>>>
>>> parser = argparse.ArgumentParser()
>>> MyArgGroup().add_arguments(parser)
"""

@abstractmethod
Expand Down
19 changes: 18 additions & 1 deletion components/src/dynamo/common/configuration/config_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,24 @@


class ConfigBase:
"""Base configuration class that allows properties with and without defaults in arbitrary order."""
"""Base configuration class that allows properties with and without defaults in arbitrary order.

Examples:
>>> import argparse
>>> from dynamo.common.configuration.config_base import ConfigBase
>>>
>>> class MyConfig(ConfigBase):
... model_name: str
... http_port: int = 8000
>>>
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument("--model-name", default="llama")
>>> parser.add_argument("--http-port", type=int, default=8000)
>>> args = parser.parse_args([])
>>> config = MyConfig.from_cli_args(args)
>>> config.http_port
8000
"""

@classmethod
def from_cli_args(cls, args: argparse.Namespace) -> Self:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,25 @@


class KvRouterConfigBase(ConfigBase):
"""Mixin carrying the 16 KvRouterConfig fields."""
"""Mixin carrying the 16 KvRouterConfig fields.

Examples:
>>> import argparse
>>> from dynamo.common.configuration.groups.kv_router_args import (
... KvRouterArgGroup,
... KvRouterConfigBase,
... )
>>>
>>> class MyRouterConfig(KvRouterConfigBase):
... endpoint: str = "http://localhost:8080"
>>>
>>> parser = argparse.ArgumentParser()
>>> KvRouterArgGroup().add_arguments(parser)
>>> config = MyRouterConfig.from_cli_args(parser.parse_args([])) # doctest: +SKIP
>>> kwargs = config.kv_router_kwargs() # doctest: +SKIP
>>> "overlap_score_weight" in kwargs # doctest: +SKIP
True
"""
Comment thread
coderabbitai[bot] marked this conversation as resolved.

overlap_score_weight: float
router_temperature: float
Expand All @@ -63,7 +81,21 @@ def kv_router_kwargs(self) -> dict:


class KvRouterArgGroup(ArgGroup):
"""CLI arguments for the 16 KvRouterConfig parameters."""
"""CLI arguments for the 16 KvRouterConfig parameters.

Examples:
>>> import argparse
>>> from dynamo.common.configuration.groups.kv_router_args import KvRouterArgGroup
>>>
>>> parser = argparse.ArgumentParser()
>>> KvRouterArgGroup().add_arguments(parser)
>>> args = parser.parse_args([
... "--router-kv-overlap-score-weight", "0.8",
... "--router-temperature", "0.5",
... ])
>>> args.overlap_score_weight
0.8

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These don't need examples, they are trivial.

"""

def add_arguments(self, parser) -> None:
g = parser.add_argument_group("KV Router Options")
Expand Down
17 changes: 17 additions & 0 deletions components/src/dynamo/common/configuration/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,23 @@ def add_argument(
"""
Add a CLI argument with env var default, optional alias and dest, and help message construction.

Examples:
>>> import argparse
>>> from dynamo.common.configuration.utils import add_argument
>>>
>>> parser = argparse.ArgumentParser()
>>> add_argument(
... parser,
... flag_name="--http-port",
... env_var="DYN_HTTP_PORT",
... default=8000,
... help="HTTP port for the engine.",
... arg_type=int,
... )
>>> args = parser.parse_args([])
>>> args.http_port
8000

Args:
parser: ArgumentParser or argument group
flag_name: Primary flag (must start with '--', e.g., "--foo")
Expand Down
20 changes: 18 additions & 2 deletions components/src/dynamo/common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,31 @@


class DisaggregationMode(Enum):
"""Disaggregation mode for LLM workers."""
"""Disaggregation mode for LLM workers.

Examples:
>>> from dynamo.common.constants import DisaggregationMode
>>> DisaggregationMode.PREFILL.value
'prefill'
>>> DisaggregationMode("agg") == DisaggregationMode.AGGREGATED
True

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, come on. It's an enum. Everyone looking at this code knows how to use an enum.

"""

AGGREGATED = "agg"
PREFILL = "prefill"
DECODE = "decode"


class EmbeddingTransferMode(Enum):
"""Embedding transfer mode for LLM workers."""
"""Embedding transfer mode for LLM workers.

Examples:
>>> from dynamo.common.constants import EmbeddingTransferMode
>>> EmbeddingTransferMode.NIXL_WRITE.value
'nixl-write'
>>> EmbeddingTransferMode("local") == EmbeddingTransferMode.LOCAL
True
"""

LOCAL = "local"
NIXL_WRITE = "nixl-write"
Expand Down
10 changes: 10 additions & 0 deletions components/src/dynamo/common/lora/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ class LoRAManager:

The manager uses the Rust-based LoRADownloader for S3 and local file sources,
and allows registering custom Python sources for other protocols.

Examples:
>>> import asyncio
>>> from dynamo.common.lora import LoRAManager
>>> manager = LoRAManager()
>>> result = asyncio.run(
... manager.download_lora("s3://bucket/adapters/lora-v1")
... ) # doctest: +SKIP
>>> manager.is_cached("s3://bucket/adapters/lora-v1") # doctest: +SKIP
True
"""

def __init__(self, cache_path: Optional[Path] = None):
Expand Down
30 changes: 30 additions & 0 deletions components/src/dynamo/common/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ def get_fs(fs_url: str) -> DirFileSystem:
Args:
fs_url: The URL of the filesystem to initialize. e.g. s3://bucket, gs://bucket, file:///local/path

Examples:
>>> from dynamo.common.storage import get_fs
>>>
>>> fs = get_fs("file:///data/media") # doctest: +SKIP
>>> protocol = fs.fs.protocol # doctest: +SKIP
>>> protocol if isinstance(protocol, str) else protocol[0] # doctest: +SKIP
'file'
>>> fs = get_fs("s3://my-bucket") # doctest: +SKIP
>>> fs.path # doctest: +SKIP
'my-bucket'
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Returns:
The initialized DirFileSystem wrapper for the filesystem.

Expand Down Expand Up @@ -81,6 +92,15 @@ def get_media_url(
``{base_url}/{storage_path}``. When *None*, the URL is constructed
from the filesystem's protocol and root path.

Examples:
>>> from dynamo.common.storage import get_fs, get_media_url # doctest: +SKIP
>>>
>>> fs = get_fs("file:///data/media") # doctest: +SKIP
>>> get_media_url(fs, "videos/req-123.mp4") # doctest: +SKIP
'file:///data/media/videos/req-123.mp4'
>>> get_media_url(fs, "img.png", base_url="https://cdn.example.com/media") # doctest: +SKIP
'https://cdn.example.com/media/img.png'

Returns:
Public URL string for the uploaded file.
"""
Expand Down Expand Up @@ -110,6 +130,16 @@ async def upload_to_fs(
data: Raw bytes to upload.
base_url: Optional CDN / proxy base URL for URL rewriting.

Examples:
>>> import asyncio
>>> from dynamo.common.storage import get_fs, upload_to_fs
>>>
>>> fs = get_fs("s3://my-media-bucket")
>>> image_bytes = b"\\x89PNG..."
>>> url = asyncio.run(
... upload_to_fs(fs, "images/req-123/output.png", image_bytes)
... ) # doctest: +SKIP

Returns:
Public URL string for the uploaded file.
"""
Expand Down
35 changes: 33 additions & 2 deletions components/src/dynamo/frontend/frontend_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,22 @@ def validate_model_path(value: str) -> str:


class FrontendConfig(KvRouterConfigBase):
"""Configuration for the Dynamo frontend."""
"""Configuration for the Dynamo frontend.

Examples:
>>> import argparse
>>> from dynamo.frontend.frontend_args import FrontendArgGroup, FrontendConfig
>>>
>>> parser = argparse.ArgumentParser()
>>> FrontendArgGroup().add_arguments(parser)
>>> args = parser.parse_args([
... "--model-name", "Llama-3.2-1B-Instruct",
... "--http-port", "8080",
... ])
>>> config = FrontendConfig.from_cli_args(args) # doctest: +SKIP
>>> config.model_name # doctest: +SKIP
'Llama-3.2-1B-Instruct'
"""

interactive: bool
kv_cache_block_size: Optional[int]
Expand Down Expand Up @@ -93,7 +108,23 @@ def _preprocess_for_encode_config(config: FrontendConfig) -> Dict[str, Any]:


class FrontendArgGroup(ArgGroup):
"""Frontend configuration parameters."""
"""Frontend configuration parameters.

Examples:
>>> import argparse
>>> from dynamo.frontend.frontend_args import FrontendArgGroup
>>>
>>> parser = argparse.ArgumentParser()
>>> group = FrontendArgGroup()
>>> group.add_arguments(parser)
>>> args = parser.parse_args([
... "--model-name", "Llama-3.2-1B-Instruct",
... "--router-mode", "kv",
... "--http-port", "8080",
... ])
>>> args.model_name
'Llama-3.2-1B-Instruct'
"""

def add_arguments(self, parser) -> None:
parser.add_argument(
Expand Down
9 changes: 9 additions & 0 deletions components/src/dynamo/mocker/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ async def worker():

Each mocker gets its own DistributedRuntime instance for true isolation,
while still sharing the same event loop and tokio runtime.

Examples:
Launch via CLI (the standard invocation pattern):

>>> # python -m dynamo.mocker --model-path /data/models/Qwen3-0.6B
>>>
>>> import uvloop # doctest: +SKIP
>>> from dynamo.mocker.main import worker # doctest: +SKIP
>>> uvloop.run(worker()) # doctest: +SKIP
"""
args = parse_args()

Expand Down
27 changes: 27 additions & 0 deletions components/src/dynamo/planner/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,23 @@ class BasePlannerDefaults:


class SLAPlannerDefaults(BasePlannerDefaults):
"""SLA-based planner defaults for throughput and latency targets.

Provides default values for SLA objectives (TTFT, ITL), load prediction,
and scaling parameters used by the planner.

Examples:
>>> from dynamo.planner.defaults import SLAPlannerDefaults
>>> SLAPlannerDefaults.ttft
500.0
>>> SLAPlannerDefaults.itl
50.0
>>> SLAPlannerDefaults.mode
'disagg'
>>> SLAPlannerDefaults.max_gpu_budget
8
"""

# Prometheus endpoint URL for pulling/querying metrics
metric_pulling_prometheus_endpoint = os.environ.get(
"PROMETHEUS_ENDPOINT",
Expand Down Expand Up @@ -143,6 +160,16 @@ class MockerComponentName:


class SubComponentType(str, Enum):
"""Type of sub-component in a disaggregated deployment.

Examples:
>>> from dynamo.planner.defaults import SubComponentType
>>> SubComponentType.PREFILL.value
'prefill'
>>> SubComponentType("decode") == SubComponentType.DECODE
True
"""

PREFILL = "prefill"
DECODE = "decode"

Expand Down
13 changes: 13 additions & 0 deletions components/src/dynamo/planner/global_planner_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ class GlobalPlannerConnector(PlannerConnector):
This connector wraps RemotePlannerClient and implements the PlannerConnector
interface, allowing planner_core.py to treat global-planner environment mode
consistently with kubernetes and virtual modes.

Examples:
>>> from dynamo.planner.global_planner_connector import GlobalPlannerConnector # doctest: +SKIP
>>>
>>> connector = GlobalPlannerConnector( # doctest: +SKIP
... runtime=runtime,
... dynamo_namespace="test-ns",
... global_planner_namespace="global-ns",
... model_name="Llama-3.2-1B-Instruct",
... )
>>> await connector._async_init() # doctest: +SKIP
>>> connector.get_model_name() # doctest: +SKIP
'Llama-3.2-1B-Instruct'
Comment thread
dagil-nvidia marked this conversation as resolved.
"""

def __init__(
Expand Down
20 changes: 20 additions & 0 deletions components/src/dynamo/planner/kubernetes_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,26 @@ class TargetReplica(BaseModel):


class KubernetesConnector(PlannerConnector):
"""Connector that manages scaling via the Kubernetes DynamoGraphDeployment API.

Implements the PlannerConnector interface for Kubernetes-based deployments,
providing add/remove component operations, deployment validation, and
model name discovery from DGD service specs.

Examples:
>>> import asyncio
>>> from dynamo.planner.kubernetes_connector import KubernetesConnector
>>> from dynamo.planner.defaults import SubComponentType
>>>
>>> connector = KubernetesConnector(
... dynamo_namespace="dynamo",
... k8s_namespace="default",
... parent_dgd_name="my-dgd",
... )
>>> asyncio.run(connector.validate_deployment()) # doctest: +SKIP
>>> model_name = connector.get_model_name() # doctest: +SKIP
"""

def __init__(
self,
dynamo_namespace: str,
Expand Down
Loading
Loading