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
24 changes: 24 additions & 0 deletions .github/workflows/fern-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,21 @@ jobs:
path: source-checkout
fetch-depth: 1

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install API doc dependencies
run: pip install -r source-checkout/docs/scripts/requirements-apidocs.txt

- name: Fernify API reference docs
working-directory: source-checkout
run: |
python3 docs/scripts/fernify_python_api.py
python3 docs/scripts/fernify_rust_api.py
python3 docs/scripts/fernify_k8s_api.py

- name: Checkout docs-website branch
uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -437,6 +452,15 @@ jobs:
echo "Created fern/pages-$TAG/"
ls -la "fern/pages-$TAG/" | head -20

- name: Update Rust API docs.rs links to release version
run: |
TAG="${{ steps.version.outputs.tag }}"
VERSION="${{ steps.version.outputs.version }}"
# Update docs.rs links from /latest to version-pinned URLs
# The Rust page was synced from pages-dev, just sed-replace the version
find "fern/pages-$TAG/api/rust" \( -name "*.md" -o -name "*.mdx" \) -exec \
sed -i "s|docs.rs/\([^/]*\)/latest|docs.rs/\1/$VERSION|g" {} +

Comment thread
coderabbitai[bot] marked this conversation as resolved.
- name: Update GitHub links to 'main' to version tag
run: |
TAG="${{ steps.version.outputs.tag }}"
Expand Down
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,22 @@


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

Examples:
>>> from dynamo.common.configuration.groups.kv_router_args import (
... KvRouterArgGroup,
... KvRouterConfigBase,
... )
>>>
>>> class MyRouterConfig(KvRouterConfigBase):
... endpoint: str = "http://localhost:8080"
>>>
>>> config = MyRouterConfig()
>>> kwargs = config.kv_router_kwargs()
>>> "overlap_score_weight" in kwargs
True
"""

overlap_score_weight: float
router_temperature: float
Expand All @@ -63,7 +78,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
"""

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
"""

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
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"""

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")
>>> protocol = fs.fs.protocol
>>> protocol if isinstance(protocol, str) else protocol[0]
'file'
>>> fs = get_fs("s3://my-bucket")
>>> fs.path
'my-bucket'
Comment on lines +49 to +58

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.

⚠️ Potential issue | 🟡 Minor

Avoid /tmp in the published examples.

file:///tmp/media is Unix-specific, so these generated docs become misleading on Windows and other non-/tmp environments. If the snippet is meant to be runnable, use tempfile; if it is illustrative only, switch to a platform-neutral placeholder path.

♻️ Proposed doc tweak
-        >>> fs = get_fs("file:///tmp/media")
+        >>> fs = get_fs("file:///path/to/media")
@@
-        >>> fs = get_fs("file:///tmp/media")
+        >>> fs = get_fs("file:///path/to/media")
@@
-        'file:///tmp/media/videos/req-123.mp4'
+        'file:///path/to/media/videos/req-123.mp4'

Based on learnings: hard-coded constants that reduce portability, including temporary paths, should be replaced with portable alternatives such as Python's tempfile module.

Also applies to: 94-99

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/src/dynamo/common/storage.py` around lines 49 - 57, Update the doc
examples using get_fs to avoid hard-coded /tmp paths: replace the
platform-specific "file:///tmp/media" example with either a platform-neutral
placeholder (e.g., "file:///path/to/media") or show how to construct a temp
directory using Python's tempfile (referencing get_fs in the examples), and
similarly update the later example range (lines 94-99) so all sample file paths
are portable across OSes.


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
>>>
>>> fs = get_fs("file:///data/media")
>>> get_media_url(fs, "videos/req-123.mp4")
'file:///data/media/videos/req-123.mp4'
>>> get_media_url(fs, "img.png", base_url="https://cdn.example.com/media")
'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
37 changes: 35 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,24 @@ 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)
>>> config.model_name
'Llama-3.2-1B-Instruct'
>>> config.http_port
8080
"""

interactive: bool
kv_cache_block_size: Optional[int]
Expand Down Expand Up @@ -93,7 +110,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
15 changes: 15 additions & 0 deletions components/src/dynamo/mocker/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,21 @@ 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
>>> from dynamo.mocker.main import worker
>>> uvloop.run(worker())

Launch multiple workers with stagger delay:

>>> # python -m dynamo.mocker \\
>>> # --model-path /data/models/Qwen3-0.6B \\
>>> # --num-workers 4 --stagger-delay 0.1
"""
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
>>>
>>> connector = GlobalPlannerConnector(
... runtime=runtime,
... dynamo_namespace="test-ns",
... global_planner_namespace="global-ns",
... model_name="Llama-3.2-1B-Instruct",
... )
>>> await connector._async_init()
>>> connector.get_model_name()
'Llama-3.2-1B-Instruct'
"""

def __init__(
Expand Down
Loading
Loading