> For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://docs.nvidia.com/dynamo/llms.txt. For full content including API reference and SDK examples, see https://docs.nvidia.com/dynamo/llms-full.txt.

# dynamo.planner

`dynamo.planner` publishes 35 classes and 1 functions. Source: [`components/src/dynamo/planner/__init__.py`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/__init__.py)

#### BackendFrameworkInvalidError (class)

Raised when the backend framework does not exist.

```python
from dynamo.planner.errors import BackendFrameworkInvalidError
```

```python
BackendFrameworkInvalidError(backend_framework: str)
```

This occurs when the DynamoGraphDeployment contains an unsupported backend framework.

[`components/src/dynamo/planner/errors.py#L155`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L155)

**Public methods**

<h4 id="api-dynamo-planner-errors-backendframeworkinvaliderror-init">
  **init**
</h4>

```python
__init__(backend_framework: str)
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L161)

#### BackendFrameworkNotFoundError (class)

Raised when the backend framework is not supported.

```python
from dynamo.planner.errors import BackendFrameworkNotFoundError
```

```python
BackendFrameworkNotFoundError()
```

This occurs when the DynamoGraphDeployment contains an unsupported backend framework.

[`components/src/dynamo/planner/errors.py#L144`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L144)

**Public methods**

<h4 id="api-dynamo-planner-errors-backendframeworknotfounderror-init">
  **init**
</h4>

```python
__init__()
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L150)

#### ComponentError (class)

Base class for component type configuration issues.

```python
from dynamo.planner.errors import ComponentError
```

This serves as a parent class for all exceptions related to
component type configuration problems in DynamoGraphDeployments.

[`components/src/dynamo/planner/errors.py#L99`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L99)

#### DeploymentModelNameMismatchError (class)

Raised when the model name is not the same in the deployment

```python
from dynamo.planner.errors import DeploymentModelNameMismatchError
```

```python
DeploymentModelNameMismatchError(prefill_model_name: str, decode_model_name: str)
```

[`components/src/dynamo/planner/errors.py#L117`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L117)

**Public methods**

<h4 id="api-dynamo-planner-errors-deploymentmodelnamemismatcherror-init">
  **init**
</h4>

```python
__init__(prefill_model_name: str, decode_model_name: str)
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L120)

#### DeploymentValidationError (class)

Raised when deployment validation fails for multiple components.

```python
from dynamo.planner.errors import DeploymentValidationError
```

```python
DeploymentValidationError(errors: List[str])
```

This is used to aggregate multiple validation errors into a single exception,
providing a comprehensive view of all validation issues.

[`components/src/dynamo/planner/errors.py#L214`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L214)

**Public methods**

<h4 id="api-dynamo-planner-errors-deploymentvalidationerror-init">
  **init**
</h4>

```python
__init__(errors: List[str])
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L221)

#### DuplicateSubComponentError (class)

Raised when multiple components have the same planner role.

```python
from dynamo.planner.errors import DuplicateSubComponentError
```

```python
DuplicateSubComponentError(sub_component_type: str, service_names: List[str])
```

This occurs when the DynamoGraphDeployment contains more than one component
with the same role, which violates the expected uniqueness constraint.

[`components/src/dynamo/planner/errors.py#L191`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L191)

**Public methods**

<h4 id="api-dynamo-planner-errors-duplicatesubcomponenterror-init">
  **init**
</h4>

```python
__init__(sub_component_type: str, service_names: List[str])
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L198)

#### DynamoGraphDeploymentNotFoundError (class)

Raised when Parent DynamoGraphDeployment cannot be found.

```python
from dynamo.planner.errors import DynamoGraphDeploymentNotFoundError
```

```python
DynamoGraphDeploymentNotFoundError(deployment_name: str, namespace: str)
```

This typically occurs when:

* The DYN\_PARENT\_DGD\_K8S\_NAME environment variable is not set
* The referenced DynamoGraphDeployment doesn't exist in the namespace

[`components/src/dynamo/planner/errors.py#L55`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L55)

**Public methods**

<h4 id="api-dynamo-planner-errors-dynamographdeploymentnotfounderror-init">
  **init**
</h4>

```python
__init__(deployment_name: str, namespace: str)
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L63)

#### DynamoGraphDeploymentNotReadyError (class)

Raised when a DynamoGraphDeployment is not ready for scaling.

```python
from dynamo.planner.errors import DynamoGraphDeploymentNotReadyError
```

```python
DynamoGraphDeploymentNotReadyError(deployment_name: str, namespace: str | None = None)
```

[`components/src/dynamo/planner/errors.py#L75`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L75)

**Public methods**

<h4 id="api-dynamo-planner-errors-dynamographdeploymentnotreadyerror-init">
  **init**
</h4>

```python
__init__(deployment_name: str, namespace: str | None = None)
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L78)

#### DynamoPlannerSweepConfigProvider (class)

Planner search-space preparation and replay-spec materialization.

```python
from dynamo.planner.simulation import DynamoPlannerSweepConfigProvider
```

[`components/src/dynamo/planner/simulation/provider.py#L256`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/simulation/provider.py#L256)

**Public methods**

<h4 id="api-dynamo-planner-simulation-provider-dynamoplannersweepconfigprovider-generate-search-space">
  generate_search_space
</h4>

```python
generate_search_space(search_spec: Mapping[str, JSONValue], context: SweepContext) -> AdapterSearchPlan
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/simulation/provider.py#L264)

<h4 id="api-dynamo-planner-simulation-provider-dynamoplannersweepconfigprovider-materialize-replay">
  materialize_replay
</h4>

```python
materialize_replay(plan: AdapterSearchPlan, selection: Mapping[str, JSONValue], context: CandidateContext) -> AdapterReplaySpec
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/simulation/provider.py#L343)

#### EmptyTargetReplicasError (class)

Raised when target\_replicas is empty or invalid.

```python
from dynamo.planner.errors import EmptyTargetReplicasError
```

```python
EmptyTargetReplicasError()
```

This occurs when attempting to set component replicas with an empty
or invalid target\_replicas dictionary.

[`components/src/dynamo/planner/errors.py#L227`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L227)

**Public methods**

<h4 id="api-dynamo-planner-errors-emptytargetreplicaserror-init">
  **init**
</h4>

```python
__init__()
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L234)

#### EngineCapabilities (class)

Static capabilities for a single engine stage (prefill or decode).

```python
from dynamo.planner.core import EngineCapabilities
```

```python
EngineCapabilities(num_gpu: Optional[int] = None, max_num_batched_tokens: Optional[int] = None, max_num_seqs: Optional[int] = None, context_length: Optional[int] = None, max_kv_tokens: Optional[int] = None, kv_cache_block_size: Optional[int] = None, speculative_nextn: Optional[int] = None, power_watts_per_replica: Optional[int] = None) -> None
```

[`components/src/dynamo/planner/core/types.py#L197`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py#L197)

**Public methods**

<h4 id="api-dynamo-planner-core-types-enginecapabilities-init">
  **init**
</h4>

```python
__init__(num_gpu: Optional[int] = None, max_num_batched_tokens: Optional[int] = None, max_num_seqs: Optional[int] = None, context_length: Optional[int] = None, max_kv_tokens: Optional[int] = None, kv_cache_block_size: Optional[int] = None, speculative_nextn: Optional[int] = None, power_watts_per_replica: Optional[int] = None) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py)

#### FpmObservations (class)

Per-engine ForwardPassMetrics keyed by (worker\_id, dp\_rank).

```python
from dynamo.planner.core import FpmObservations
```

```python
FpmObservations(prefill: Optional[dict[tuple[str, int], ForwardPassMetrics]] = None, decode: Optional[dict[tuple[str, int], ForwardPassMetrics]] = None) -> None
```

[`components/src/dynamo/planner/core/types.py#L74`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py#L74)

**Public methods**

<h4 id="api-dynamo-planner-core-types-fpmobservations-init">
  **init**
</h4>

```python
__init__(prefill: Optional[dict[tuple[str, int], ForwardPassMetrics]] = None, decode: Optional[dict[tuple[str, int], ForwardPassMetrics]] = None) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py)

#### GlobalPlannerConnector (class)

Connector that delegates scaling decisions to a centralized GlobalPlanner.

```python
from dynamo.planner import GlobalPlannerConnector
```

```python
GlobalPlannerConnector(runtime: DistributedRuntime, dynamo_namespace: str, global_planner_namespace: str, global_planner_component: str = 'GlobalPlanner', model_name: Optional[str] = None)
```

This connector wraps RemotePlannerClient and implements the InfraScaler
interface, allowing planner\_core.py to treat global-planner environment mode
consistently with kubernetes and virtual modes.

[`components/src/dynamo/planner/connectors/global_planner.py#L37`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/global_planner.py#L37)

**Public methods**

<h4 id="api-dynamo-planner-connectors-global-planner-globalplannerconnector-init">
  **init**
</h4>

```python
__init__(runtime: DistributedRuntime, dynamo_namespace: str, global_planner_namespace: str, global_planner_component: str = 'GlobalPlanner', model_name: Optional[str] = None)
```

Initialize GlobalPlannerConnector.

**Parameters**

**`runtime`** `DistributedRuntime`

Distributed runtime for communication

---

**`dynamo_namespace`** `str`

Local dynamo namespace (caller identification)

---

**`global_planner_namespace`** `str`

Namespace where GlobalPlanner is deployed

---

**`global_planner_component`** `str`

Component name of GlobalPlanner (default: "GlobalPlanner")

---

**`model_name`** `Optional[str]`

Optional model name (will be managed remotely if not provided)

---

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/global_planner.py#L46)

<h4 id="api-dynamo-planner-connectors-global-planner-globalplannerconnector-async-init">
  async_init
</h4>

```python
async_init()
```

Async initialization - creates RemotePlannerClient

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/global_planner.py#L81)

<h4 id="api-dynamo-planner-connectors-global-planner-globalplannerconnector-set-predicted-load">
  set_predicted_load
</h4>

```python
set_predicted_load(num_requests: Optional[float], isl: Optional[float], osl: Optional[float])
```

Set predicted load for inclusion in next scale request.

This is called by planner\_core.py before calling set\_component\_replicas.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/global_planner.py#L92)

<h4 id="api-dynamo-planner-connectors-global-planner-globalplannerconnector-set-component-replicas">
  set_component_replicas
</h4>

```python
set_component_replicas(target_replicas: list[TargetReplica], blocking: bool = True)
```

Set component replicas by delegating to GlobalPlanner.

Sends a ScaleRequest to the GlobalPlanner with the target replica configurations.

**Parameters**

**`target_replicas`** `list[TargetReplica]`

List of target replica configurations

---

**`blocking`** `bool`

Whether to wait for scaling completion (passed to GlobalPlanner)

---

**Raises**

* `EmptyTargetReplicasError` — If target\_replicas is empty
* `RuntimeError` — If remote\_client is not initialized or the response indicates a hard error (e.g., authorization denied, K8s exception). A REJECTED response is NOT raised — it is logged as a warning and treated as a no-op for this tick.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/global_planner.py#L106)

<h4 id="api-dynamo-planner-connectors-global-planner-globalplannerconnector-add-component">
  add_component
</h4>

```python
add_component(sub_component_type: SubComponentType, blocking: bool = True)
```

Add a component (not supported for GlobalPlanner).

GlobalPlanner only supports batch operations via set\_component\_replicas.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/global_planner.py#L182)

<h4 id="api-dynamo-planner-connectors-global-planner-globalplannerconnector-remove-component">
  remove_component
</h4>

```python
remove_component(sub_component_type: SubComponentType, blocking: bool = True)
```

Remove a component (not supported for GlobalPlanner).

GlobalPlanner only supports batch operations via set\_component\_replicas.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/global_planner.py#L195)

<h4 id="api-dynamo-planner-connectors-global-planner-globalplannerconnector-validate-deployment">
  validate_deployment
</h4>

```python
validate_deployment(prefill_component_name: Optional[str] = None, decode_component_name: Optional[str] = None, require_prefill: bool = True, require_decode: bool = True) -> None
```

Validate deployment (no-op for GlobalPlanner).

The GlobalPlanner validates the deployment on its side, so local
validation is not needed in delegating mode.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/global_planner.py#L208)

<h4 id="api-dynamo-planner-connectors-global-planner-globalplannerconnector-wait-for-deployment-ready">
  wait_for_deployment_ready
</h4>

```python
wait_for_deployment_ready(include_planner: bool = True)
```

Wait for the pool's own workers to be ready.

Even though GlobalPlanner handles cluster-wide orchestration, the
pool Planner still reads its own workers' DynamoWorkerMetadata CRs
for capability discovery (`get_worker_info`). Without a local
wait, `_async_init` runs within milliseconds of pod entry — long
before workers register MDC — so `get_worker_info` falls back to
defaults with `context_length` / `max_kv_tokens` unset and
load-scaling silently disables itself for the pod's lifetime.

Mirror the standalone path by delegating to the pool-local
KubernetesConnector. If no local connector is available (e.g.
running outside a cluster), fall back to the previous no-op so
out-of-cluster callers are not blocked.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/global_planner.py#L226)

<h4 id="api-dynamo-planner-connectors-global-planner-globalplannerconnector-get-actual-worker-counts">
  get_actual_worker_counts
</h4>

```python
get_actual_worker_counts(prefill_component_name: Optional[str] = None, decode_component_name: Optional[str] = None) -> tuple[int, int, bool]
```

Read ready replica counts and rollout stability from the pool's own DGD.

GlobalPlanner orchestrates scaling, but the pool Planner pod has direct
access to its own DGD status. Mirror KubernetesConnector by delegating
to the pool-local connector so `_scaling_in_progress` observes real
rollouts instead of always seeing `is_stable=True`.

Returns `(0, 0, True)` when no local KubernetesConnector is available
(e.g. running out-of-cluster), matching the existing capability-discovery
fallback path so out-of-cluster callers aren't blocked.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/global_planner.py#L282)

<h4 id="api-dynamo-planner-connectors-global-planner-globalplannerconnector-get-worker-runtime-namespace">
  get_worker_runtime_namespace
</h4>

```python
get_worker_runtime_namespace(base_dynamo_namespace: str) -> str
```

Resolve the pool-local worker runtime namespace when available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/global_planner.py#L310)

<h4 id="api-dynamo-planner-connectors-global-planner-globalplannerconnector-get-gpu-counts">
  get_gpu_counts
</h4>

```python
get_gpu_counts(require_prefill: bool = True, require_decode: bool = True) -> tuple[Optional[int], Optional[int]]
```

Resolve pool-local GPU shape when available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/global_planner.py#L317)

<h4 id="api-dynamo-planner-connectors-global-planner-globalplannerconnector-get-worker-info">
  get_worker_info
</h4>

```python
get_worker_info(sub_component_type: SubComponentType, backend: str = 'vllm') -> WorkerInfo
```

Resolve per-worker capabilities from the pool's own MDC/DGD.

Without this, `resolve_worker_info` falls through to
`build_worker_info_from_defaults` which leaves `context_length`
and `max_kv_tokens` unset, and load\_scaling's easy-mode decisions
bail out every tick — so the pool Planner silently sends no
ScaleRequests.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/global_planner.py#L331)

<h4 id="api-dynamo-planner-connectors-global-planner-globalplannerconnector-get-model-name">
  get_model_name
</h4>

```python
get_model_name(require_prefill: bool = True, require_decode: bool = True) -> str
```

Get model name.

Prefers the value provided at init time, then the pool's own DGD
container args (via the local KubernetesConnector), and finally
falls back to a placeholder indicating the model is managed
remotely.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/global_planner.py#L349)

#### KubernetesConnector (class)

No summary available.

```python
from dynamo.planner import KubernetesConnector
```

```python
KubernetesConnector(dynamo_namespace: str, model_name: Optional[str] = None, k8s_namespace: Optional[str] = None, parent_dgd_name: Optional[str] = None, raise_not_ready: bool = False)
```

[`components/src/dynamo/planner/connectors/kubernetes.py#L66`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L66)

**Public methods**

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-init">
  **init**
</h4>

```python
__init__(dynamo_namespace: str, model_name: Optional[str] = None, k8s_namespace: Optional[str] = None, parent_dgd_name: Optional[str] = None, raise_not_ready: bool = False)
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L67)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-async-init">
  async_init
</h4>

```python
async_init()
```

No-op asynchronous lifecycle hook.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L98)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-get-worker-runtime-namespace">
  get_worker_runtime_namespace
</h4>

```python
get_worker_runtime_namespace(base_dynamo_namespace: str) -> str
```

Return the Dynamo namespace used by the current worker generation.

Newer operators publish the effective runtime namespace on the worker
component status. Older operators expose only the active worker hash, so
the planner falls back to appending that hash only for Deployment-backed
and LeaderWorkerSet-backed workers.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L102)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-add-component">
  add_component
</h4>

```python
add_component(sub_component_type: SubComponentType, blocking: bool = True)
```

Add a component by increasing its replica count by 1

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L171)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-remove-component">
  remove_component
</h4>

```python
remove_component(sub_component_type: SubComponentType, blocking: bool = True)
```

Remove a component by decreasing its replica count by 1

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L189)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-validate-deployment">
  validate_deployment
</h4>

```python
validate_deployment(prefill_component_name: Optional[str] = None, decode_component_name: Optional[str] = None, require_prefill: bool = True, require_decode: bool = True)
```

Verify that the deployment contains prefill/decode components and the model name exists. Allows explicit component-name overrides when the caller provides them.

**Raises**

* `DynamoGraphDeploymentNotFoundError` — If the deployment is not found
* `DeploymentValidationError` — If the deployment does not contain required prefill/decode components

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L208)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-get-model-name">
  get_model_name
</h4>

```python
get_model_name(require_prefill: bool = True, require_decode: bool = True) -> str
```

Get the model name from the current deployment.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L262)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-get-graph-deployment">
  get_graph_deployment
</h4>

```python
get_graph_deployment() -> dict
```

Fetch the DGD once for callers that share it across GPU/power reads.

Not on the base `PlannerConnector` protocol — power awareness is
Kubernetes-local and must not expand that ABC. The environment checks
`is_power_aware_connector(controller)` (all four methods present)
rather than duck-typing via `getattr`.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L349)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-get-gpu-counts">
  get_gpu_counts
</h4>

```python
get_gpu_counts(require_prefill: bool = True, require_decode: bool = True, deployment: Optional[dict] = None) -> tuple[int, int]
```

Get the GPU counts for prefill and decode components.

Pass `deployment` to reuse an already-fetched DGD (avoids a second
GET when the environment also resolves power configs on the same tick).

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L359)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-get-component-power-configs">
  get_component_power_configs
</h4>

```python
get_component_power_configs(require_prefill: bool = True, require_decode: bool = True, prefill_component_name: Optional[str] = None, decode_component_name: Optional[str] = None, deployment: Optional[dict] = None) -> tuple[Optional[ComponentPowerConfig], Optional[ComponentPowerConfig]]
```

Resolve DGD-owned per-role power configs from worker podTemplate annotations.

One DGD GET unless `deployment` is provided (shared with
`get_gpu_counts` on the same tick). `watts_per_replica` on each
config uses the replica-wide GPU total (nodeCount × per-pod) via
`Service.get_total_gpu_count()`, independent of the per-pod
`num_gpus` the GPU-budget math consumes.

The typed parser errors (`PowerAnnotationMissingError` /
`PowerAnnotationInvalidError` / `SubComponentNotFoundError` /
`DuplicateSubComponentError` / `ValueError` for a bad GPU count)
propagate so the environment can apply the startup-fail vs
runtime-conservative policy rather than the planner guessing a cap.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L426)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-get-frontend-metrics-url">
  get_frontend_metrics_url
</h4>

```python
get_frontend_metrics_url(port: int = 8000) -> Optional[str]
```

Auto-discover the frontend component's metrics URL from the DGD.

Iterates DGD components to find the component with type "frontend",
then constructs the in-cluster URL using the operator's naming convention:
http\://\{dgd\_name}-\{component\_name\_lowercase}:\{port}/metrics

**Returns**

* `Optional[str]` — The metrics URL string, or None if no frontend component is found.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L458)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-wait-for-deployment-ready">
  wait_for_deployment_ready
</h4>

```python
wait_for_deployment_ready(include_planner: bool = True)
```

Wait for the deployment to be ready (legacy replica-stability path).

Does **not** check pod annotation convergence or require
`observedGeneration` catch-up. Power-aware callers that permanently
cache DGD fields must use `wait_for_settled_graph_deployment`
instead.

**Parameters**

**`include_planner`** `bool`

If False, skip the planner component when checking
readiness. This lets the planner read MDC from worker pods
without waiting for itself to be marked ready in the DGD.

---

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L480)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-wait-for-settled-graph-deployment">
  wait_for_settled_graph_deployment
</h4>

```python
wait_for_settled_graph_deployment(include_planner: bool = False, *, require_prefill: bool = True, require_decode: bool = True, prefill_component_name: Optional[str] = None, decode_component_name: Optional[str] = None) -> dict
```

Wait for a settled DGD snapshot and return that same object.

When `include_planner` is False, the snapshot has:

* non-planner worker replica counts stable (desired == updated == ready)
* `status.observedGeneration >= metadata.generation`
* every non-terminal worker Pod carries the expected
  `dynamo.nvidia.com/gpu-power-limit` annotation from the current
  DGD snapshot, confirming the operator has propagated the DGD intent
  to running Pods (hardware enforcement by the Power Agent/NVML is
  separate and not verified here)

Power-relevant workers are selected with the same role/name resolution
as `get_component_power_configs` (typed roles, explicit-name
fallback for untyped workers, unique generic `type: worker` for agg).

Callers that permanently cache fields from the DGD (power caps) must
use this snapshot rather than issuing a later GET, so an
annotation-only generation bump cannot be adopted before workers
have rolled onto that generation. Active rolling updates
(`status.rollingUpdate.phase` Pending/InProgress/Failed) also
block settlement because old Pods still carry the previous cap.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L499)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-get-worker-info">
  get_worker_info
</h4>

```python
get_worker_info(sub_component_type: SubComponentType, backend: str = 'vllm') -> WorkerInfo
```

Get WorkerInfo for a sub-component, trying MDC first, then fallbacks.

**Parameters**

**`sub_component_type`** `SubComponentType`

PREFILL or DECODE

---

**`backend`** `str`

Backend framework name (for default fallback)

---

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L656)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-get-actual-worker-counts">
  get_actual_worker_counts
</h4>

```python
get_actual_worker_counts(prefill_component_name: Optional[str] = None, decode_component_name: Optional[str] = None) -> tuple[int, int, bool]
```

Get ready worker counts from DGD status without listing Pods.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L726)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-get-power-aware-worker-counts">
  get_power_aware_worker_counts
</h4>

```python
get_power_aware_worker_counts(prefill_component_name: Optional[str] = None, decode_component_name: Optional[str] = None) -> tuple[int, int, bool]
```

Get power-safe worker counts without blocking the Planner event loop.

One thread dispatch contains the synchronous DGD GET and the single
DGD-scoped Pod LIST. The returned Pod snapshot is partitioned locally by
component before terminating-Pod checks run.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L739)

<h4 id="api-dynamo-planner-connectors-kubernetes-kubernetesconnector-set-component-replicas">
  set_component_replicas
</h4>

```python
set_component_replicas(target_replicas: list[TargetReplica], blocking: bool = True)
```

Set the replicas for multiple components at once

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/kubernetes.py#L851)

#### ModelNameNotFoundError (class)

Raised when the model name is not found in the deployment

```python
from dynamo.planner.errors import ModelNameNotFoundError
```

```python
ModelNameNotFoundError()
```

[`components/src/dynamo/planner/errors.py#L109`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L109)

**Public methods**

<h4 id="api-dynamo-planner-errors-modelnamenotfounderror-init">
  **init**
</h4>

```python
__init__()
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L112)

#### PlannerConnector (class)

Deployment-control interface the planner uses to inspect and scale one deployment.

```python
from dynamo.planner import PlannerConnector
```

`construct_connector` selects one implementation per
`PlannerConfig.environment`: `KubernetesConnector` scales through the DGD
scaling adapter's `Scale` subresource and falls back to patching DGD replica
counts directly when no adapter exists, `VirtualConnector` publishes
decisions through the runtime coordinator for the deployment environment to
apply, and `GlobalPlannerConnector` forwards them to a centralized
GlobalPlanner.
`PlannerEnvironmentImpl.initialize` drives `async_init`, then
`validate_deployment`, then `wait_for_deployment_ready`; `async_init`
has to run first, because `GlobalPlannerConnector.set_component_replicas`
raises `RuntimeError` until it holds a remote client.

A clean return is not proof of the outcome. `validate_deployment` inspects
the deployment only under Kubernetes and is a no-op in the other two modes.
`get_gpu_counts` yields `(None, None)` from `VirtualConnector` always
and from `GlobalPlannerConnector` when it holds no pool-local Kubernetes
connector, while the Kubernetes implementation narrows the return to
`tuple[int, int]` and raises `DeploymentValidationError` rather than
reporting an unknown shape. `get_model_name` can return the placeholder
`"managed-remotely"` under a global planner.
`set_component_replicas` may log and return without scaling when the
deployment is not ready or the global planner rejects the request, though all
three implementations do raise `EmptyTargetReplicasError` on an empty target
list. `get_actual_worker_counts` reports `0` for a component whose name
argument is `None` rather than a deployment-wide total.

Being a `Protocol` rather than an ABC, every method body here is `pass`.
All three implementations subclass it explicitly, so an override that is
missing or misnamed returns `None` at runtime instead of raising. The
surface callers rely on is also wider than what is declared here:
`construct_environment` feature-detects `get_worker_runtime_namespace`,
which all three connectors provide.

[`components/src/dynamo/planner/connectors/base.py#L32`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/base.py#L32)

**Public methods**

<h4 id="api-dynamo-planner-connectors-base-plannerconnector-async-init">
  async_init
</h4>

```python
async_init() -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/base.py#L69)

<h4 id="api-dynamo-planner-connectors-base-plannerconnector-validate-deployment">
  validate_deployment
</h4>

```python
validate_deployment(prefill_component_name: Optional[str] = None, decode_component_name: Optional[str] = None, require_prefill: bool = True, require_decode: bool = True) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/base.py#L72)

<h4 id="api-dynamo-planner-connectors-base-plannerconnector-wait-for-deployment-ready">
  wait_for_deployment_ready
</h4>

```python
wait_for_deployment_ready(include_planner: bool = True) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/base.py#L81)

<h4 id="api-dynamo-planner-connectors-base-plannerconnector-get-model-name">
  get_model_name
</h4>

```python
get_model_name(require_prefill: bool = True, require_decode: bool = True) -> str
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/base.py#L84)

<h4 id="api-dynamo-planner-connectors-base-plannerconnector-get-gpu-counts">
  get_gpu_counts
</h4>

```python
get_gpu_counts(require_prefill: bool = True, require_decode: bool = True) -> tuple[Optional[int], Optional[int]]
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/base.py#L91)

<h4 id="api-dynamo-planner-connectors-base-plannerconnector-get-actual-worker-counts">
  get_actual_worker_counts
</h4>

```python
get_actual_worker_counts(prefill_component_name: Optional[str] = None, decode_component_name: Optional[str] = None) -> tuple[int, int, bool]
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/base.py#L98)

<h4 id="api-dynamo-planner-connectors-base-plannerconnector-set-component-replicas">
  set_component_replicas
</h4>

```python
set_component_replicas(target_replicas: list[TargetReplica], blocking: bool = True) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/base.py#L105)

#### PlannerEffects (class)

What the core returns after processing a tick.

```python
from dynamo.planner.core import PlannerEffects
```

```python
PlannerEffects(scale_to: Optional[ScalingDecision] = None, next_tick: Optional[ScheduledTick] = None, diagnostics: TickDiagnostics = TickDiagnostics()) -> None
```

[`components/src/dynamo/planner/core/types.py#L188`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py#L188)

**Public methods**

<h4 id="api-dynamo-planner-core-types-plannereffects-init">
  **init**
</h4>

```python
__init__(scale_to: Optional[ScalingDecision] = None, next_tick: Optional[ScheduledTick] = None, diagnostics: TickDiagnostics = TickDiagnostics()) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py)

#### PlannerError (class)

Base exception for all planner-related errors.

```python
from dynamo.planner.errors import PlannerError
```

This serves as the root exception class for all custom exceptions
in the planner module, allowing for broad exception catching when needed.

[`components/src/dynamo/planner/errors.py#L45`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L45)

#### PlannerScalingState (class)

Shared in-memory scaling state for all planner modes.

```python
from dynamo.planner.core import PlannerScalingState
```

```python
PlannerScalingState(config: PlannerConfig, capabilities: Optional[WorkerCapabilities] = None) -> None
```

Owns perf models, throughput lower bounds, worker inventory,
last-value runtime metadata, and all scaling decision logic. It
deliberately has no runtime dependencies. Load prediction state
lives in the builtin PREDICT plugin and is passed in explicitly.

Builtin orchestrator plugins use this class directly as their private
shared core while the remaining cross-plugin state is being split into
explicit pipeline artifacts.

[`components/src/dynamo/planner/core/state_machine.py#L48`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/state_machine.py#L48)

**Public methods**

<h4 id="api-dynamo-planner-core-state-machine-plannerscalingstate-init">
  **init**
</h4>

```python
__init__(config: PlannerConfig, capabilities: Optional[WorkerCapabilities] = None) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/state_machine.py#L61)

<h4 id="api-dynamo-planner-core-state-machine-plannerscalingstate-update-capabilities">
  update_capabilities
</h4>

```python
update_capabilities(capabilities: WorkerCapabilities) -> None
```

Replace the current worker capabilities.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/state_machine.py#L134)

<h4 id="api-dynamo-planner-core-state-machine-plannerscalingstate-load-benchmark-fpms">
  load_benchmark_fpms
</h4>

```python
load_benchmark_fpms(prefill_fpms: Optional[list[ForwardPassMetrics]] = None, decode_fpms: Optional[list[ForwardPassMetrics]] = None, agg_fpms: Optional[list[ForwardPassMetrics]] = None) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/state_machine.py#L155)

<h4 id="api-dynamo-planner-core-state-machine-plannerscalingstate-begin-tick">
  begin_tick
</h4>

```python
begin_tick() -> None
```

Reset per-tick diagnostics before builtin plugins run.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/state_machine.py#L176)

<h4 id="api-dynamo-planner-core-state-machine-plannerscalingstate-observe-worker-counts">
  observe_worker_counts
</h4>

```python
observe_worker_counts(counts: WorkerCounts) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/state_machine.py#L180)

<h4 id="api-dynamo-planner-core-state-machine-plannerscalingstate-observe-fpm">
  observe_fpm
</h4>

```python
observe_fpm(obs: FpmObservations) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/state_machine.py#L183)

<h4 id="api-dynamo-planner-core-state-machine-plannerscalingstate-observe-runtime-metadata">
  observe_runtime_metadata
</h4>

```python
observe_runtime_metadata(*, kv_hit_rate: Optional[float] = None, accept_length: Optional[float] = None) -> None
```

Update last-value runtime metadata without touching prediction history.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/state_machine.py#L188)

<h4 id="api-dynamo-planner-core-state-machine-plannerscalingstate-install-regressions">
  install_regressions
</h4>

```python
install_regressions(*, prefill: Optional[PlannerEnginePerfModel] = None, decode: Optional[PlannerEnginePerfModel] = None, agg: Optional[PlannerEnginePerfModel] = None) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/state_machine.py#L199)

<h4 id="api-dynamo-planner-core-state-machine-plannerscalingstate-advance-load">
  advance_load
</h4>

```python
advance_load(obs: FpmObservations, *, predicted_kv_hit_rate: Optional[float] = None, predicted_accept_length: Optional[float] = None) -> Optional[ScalingDecision]
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/state_machine.py#L213)

<h4 id="api-dynamo-planner-core-state-machine-plannerscalingstate-advance-throughput-from-prediction">
  advance_throughput_from_prediction
</h4>

```python
advance_throughput_from_prediction(traffic: TrafficObservation, *, predicted_num_req: Optional[float], predicted_isl: Optional[float], predicted_osl: Optional[float], predicted_kv_hit_rate: Optional[float], predicted_accept_length: Optional[float] = None) -> Optional[ScalingDecision]
```

Run the throughput decision using PREDICT-stage output.

The PREDICT plugin owns load prediction history. This method consumes
only explicit prediction output so PROPOSE never re-runs prediction or
depends on hidden predictor state.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/state_machine.py#L226)

<h4 id="api-dynamo-planner-core-state-machine-plannerscalingstate-diagnostics">
  diagnostics
</h4>

```python
diagnostics() -> TickDiagnostics
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/state_machine.py#L281)

#### PowerAnnotationInvalidError (class)

Raised when a per-GPU power-limit annotation is not a positive integer.

```python
from dynamo.planner.errors import PowerAnnotationInvalidError
```

```python
PowerAnnotationInvalidError(component_name: str, value: str)
```

The annotation value is watts and must parse to an integer `> 0`. Empty,
non-numeric, zero, or negative values are configuration errors — the
planner cannot compute a power budget from them and refuses to silently
substitute a default.

[`components/src/dynamo/planner/errors.py#L266`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L266)

**Public methods**

<h4 id="api-dynamo-planner-errors-powerannotationinvaliderror-init">
  **init**
</h4>

```python
__init__(component_name: str, value: str)
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L275)

#### PowerAnnotationMissingError (class)

Raised when a worker component has no per-GPU power-limit annotation.

```python
from dynamo.planner.errors import PowerAnnotationMissingError
```

```python
PowerAnnotationMissingError(component_name: str)
```

The per-GPU cap is authored on the worker component's
`podTemplate.metadata.annotations` (key
`dynamo.nvidia.com/gpu-power-limit`); a missing key means the DGD did not
declare a cap for this role. When power awareness is enabled every managed
worker role must carry one, so the planner fails closed rather than
guessing a cap.

[`components/src/dynamo/planner/errors.py#L241`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L241)

**Public methods**

<h4 id="api-dynamo-planner-errors-powerannotationmissingerror-init">
  **init**
</h4>

```python
__init__(component_name: str)
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L252)

#### RolloutFailedError (class)

Raised when the operator marks a DGD rolling update as Failed.

```python
from dynamo.planner.errors import RolloutFailedError
```

```python
RolloutFailedError(deployment_name: str, reason: str = '')
```

Failed is a terminal rollout state (the operator sets `endTime`).
Retrying until a generic timeout would leave the planner stuck for up to
30 minutes; instead we surface this as an immediate actionable error so
the operator or user can investigate and recover.

[`components/src/dynamo/planner/errors.py#L292`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L292)

**Public methods**

<h4 id="api-dynamo-planner-errors-rolloutfailederror-init">
  **init**
</h4>

```python
__init__(deployment_name: str, reason: str = '')
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L301)

#### SLAPlannerDefaults (class)

No summary available.

```python
from dynamo.planner import SLAPlannerDefaults
```

[`components/src/dynamo/planner/config/defaults.py#L44`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/config/defaults.py#L44)

#### ScalingDecision (class)

Desired replica counts. `None` means the core has no opinion on that component (e.g. prefill-only planner leaves decode as None).

```python
from dynamo.planner.core import ScalingDecision
```

```python
ScalingDecision(num_prefill: Optional[int] = None, num_decode: Optional[int] = None) -> None
```

[`components/src/dynamo/planner/core/types.py#L96`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py#L96)

**Public methods**

<h4 id="api-dynamo-planner-core-types-scalingdecision-init">
  **init**
</h4>

```python
__init__(num_prefill: Optional[int] = None, num_decode: Optional[int] = None) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py)

#### ScheduledTick (class)

Declares when the core next needs to be called, what data it needs, and what decisions to make.

```python
from dynamo.planner.core import ScheduledTick
```

```python
ScheduledTick(at_s: float, run_load_scaling: bool = False, run_throughput_scaling: bool = False, need_traffic_metrics: bool = False, use_full_traffic_metrics: bool = False, traffic_metrics_duration_s: float = 0.0, need_worker_states: bool = False, need_worker_fpm: bool = False, at_monotonic_s: Optional[float] = None) -> None
```

`at_s` is an absolute wall-clock time for the native adapter and a
simulated time for replay. `at_monotonic_s` is the matching scheduler
timestamp used to make observation-prefetch and plugin-dispatch cadence
decisions against the same clock value.

[`components/src/dynamo/planner/core/types.py#L21`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py#L21)

**Public methods**

<h4 id="api-dynamo-planner-core-types-scheduledtick-init">
  **init**
</h4>

```python
__init__(at_s: float, run_load_scaling: bool = False, run_throughput_scaling: bool = False, need_traffic_metrics: bool = False, use_full_traffic_metrics: bool = False, traffic_metrics_duration_s: float = 0.0, need_worker_states: bool = False, need_worker_fpm: bool = False, at_monotonic_s: Optional[float] = None) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py)

#### SubComponentNotFoundError (class)

Raised when a required component role is not found in the deployment.

```python
from dynamo.planner.errors import SubComponentNotFoundError
```

```python
SubComponentNotFoundError(sub_component_type: str)
```

This occurs when the DynamoGraphDeployment doesn't contain any component
with the requested role (e.g., 'prefill', 'decode').

[`components/src/dynamo/planner/errors.py#L168`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L168)

**Public methods**

<h4 id="api-dynamo-planner-errors-subcomponentnotfounderror-init">
  **init**
</h4>

```python
__init__(sub_component_type: str)
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L175)

#### SubComponentType (class)

No summary available.

```python
from dynamo.planner import SubComponentType
```

[`components/src/dynamo/planner/config/defaults.py#L123`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/config/defaults.py#L123)

#### TargetReplica (class)

No summary available.

```python
from dynamo.planner import TargetReplica
```

[`components/src/dynamo/planner/config/defaults.py#L128`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/config/defaults.py#L128)

#### TickInput (class)

What the adapter provides to the core on each tick.

```python
from dynamo.planner.core import TickInput
```

```python
TickInput(now_s: float, traffic: Optional[TrafficObservation] = None, worker_counts: Optional[WorkerCounts] = None, fpm_observations: Optional[FpmObservations] = None) -> None
```

Fields are filled according to the previous `ScheduledTick`'s
declared requirements.

[`components/src/dynamo/planner/core/types.py#L82`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py#L82)

**Public methods**

<h4 id="api-dynamo-planner-core-types-tickinput-init">
  **init**
</h4>

```python
__init__(now_s: float, traffic: Optional[TrafficObservation] = None, worker_counts: Optional[WorkerCounts] = None, fpm_observations: Optional[FpmObservations] = None) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py)

#### TrafficObservation (class)

Aggregated traffic metrics over an observation window.

```python
from dynamo.planner.core import TrafficObservation
```

```python
TrafficObservation(duration_s: float, num_req: float, isl: float, osl: float, kv_hit_rate: Optional[float] = None, accept_length: Optional[float] = None) -> None
```

[`components/src/dynamo/planner/core/types.py#L50`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py#L50)

**Public methods**

<h4 id="api-dynamo-planner-core-types-trafficobservation-init">
  **init**
</h4>

```python
__init__(duration_s: float, num_req: float, isl: float, osl: float, kv_hit_rate: Optional[float] = None, accept_length: Optional[float] = None) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py)

#### UserProvidedModelNameMismatchError (class)

Raised when the model name is not the same as the user provided model name

```python
from dynamo.planner.errors import UserProvidedModelNameMismatchError
```

```python
UserProvidedModelNameMismatchError(model_name: str, user_provided_model_name: str)
```

[`components/src/dynamo/planner/errors.py#L132`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L132)

**Public methods**

<h4 id="api-dynamo-planner-errors-userprovidedmodelnamemismatcherror-init">
  **init**
</h4>

```python
__init__(model_name: str, user_provided_model_name: str)
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/errors.py#L135)

#### VirtualConnector (class)

Coordinate planner scaling decisions for non-native environments.

```python
from dynamo.planner import VirtualConnector
```

```python
VirtualConnector(runtime: DistributedRuntime, dynamo_namespace: str, worker_info_provider: WorkerInfoProvider, model_name: Optional[str] = None)
```

The connector does not scale a deployment directly. It publishes decisions
through the Dynamo runtime's `VirtualConnectorCoordinator`; the deployment
environment consumes them with `VirtualConnectorClient` and reports scaling
status back to the coordinator.

Virtual deployments do not have a Kubernetes API from which to derive worker
component and endpoint metadata. They therefore require a
`worker_info_provider` that resolves `WorkerInfo` from runtime MDC. The
planner factory normally supplies its `RuntimeFpmProvider`, sharing the same
runtime discovery source used for forward-pass metrics.

[`components/src/dynamo/planner/connectors/virtual.py#L30`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/virtual.py#L30)

**Public methods**

<h4 id="api-dynamo-planner-connectors-virtual-virtualconnector-init">
  **init**
</h4>

```python
__init__(runtime: DistributedRuntime, dynamo_namespace: str, worker_info_provider: WorkerInfoProvider, model_name: Optional[str] = None)
```

Initialize a virtual deployment connector.

**Parameters**

**`runtime`** `DistributedRuntime`

Distributed runtime used for coordination and discovery.

---

**`dynamo_namespace`** `str`

Namespace containing the virtual deployment.

---

**`worker_info_provider`** `WorkerInfoProvider`

Required source of runtime WorkerInfo/MDC used
to locate worker endpoints. `construct_environment` normally
provides a `RuntimeFpmProvider`.

---

**`model_name`** `Optional[str]`

Model name reported by the deployment.

---

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/virtual.py#L45)

<h4 id="api-dynamo-planner-connectors-virtual-virtualconnector-get-worker-info">
  get_worker_info
</h4>

```python
get_worker_info(sub_component_type: SubComponentType, backend: str = 'vllm') -> WorkerInfo
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/virtual.py#L81)

<h4 id="api-dynamo-planner-connectors-virtual-virtualconnector-async-init">
  async_init
</h4>

```python
async_init()
```

Async initialization that must be called after **init**

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/virtual.py#L92)

<h4 id="api-dynamo-planner-connectors-virtual-virtualconnector-add-component">
  add_component
</h4>

```python
add_component(sub_component_type: SubComponentType, blocking: bool = True)
```

Add a component by increasing its replica count by 1

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/virtual.py#L106)

<h4 id="api-dynamo-planner-connectors-virtual-virtualconnector-remove-component">
  remove_component
</h4>

```python
remove_component(sub_component_type: SubComponentType, blocking: bool = True)
```

Remove a component by decreasing its replica count by 1

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/virtual.py#L126)

<h4 id="api-dynamo-planner-connectors-virtual-virtualconnector-set-component-replicas">
  set_component_replicas
</h4>

```python
set_component_replicas(target_replicas: list[TargetReplica], blocking: bool = True)
```

Set the replicas for multiple components at once

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/virtual.py#L148)

<h4 id="api-dynamo-planner-connectors-virtual-virtualconnector-validate-deployment">
  validate_deployment
</h4>

```python
validate_deployment(prefill_component_name: Optional[str] = None, decode_component_name: Optional[str] = None, require_prefill: bool = True, require_decode: bool = True)
```

Validate the deployment

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/virtual.py#L175)

<h4 id="api-dynamo-planner-connectors-virtual-virtualconnector-wait-for-deployment-ready">
  wait_for_deployment_ready
</h4>

```python
wait_for_deployment_ready(include_planner: bool = True)
```

Wait for the deployment to be ready

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/virtual.py#L185)

<h4 id="api-dynamo-planner-connectors-virtual-virtualconnector-get-worker-runtime-namespace">
  get_worker_runtime_namespace
</h4>

```python
get_worker_runtime_namespace(base_dynamo_namespace: str) -> str
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/virtual.py#L190)

<h4 id="api-dynamo-planner-connectors-virtual-virtualconnector-get-actual-worker-counts">
  get_actual_worker_counts
</h4>

```python
get_actual_worker_counts(prefill_component_name: Optional[str] = None, decode_component_name: Optional[str] = None) -> tuple[int, int, bool]
```

Read active workers from discovery and scaling status from the client ack.

Coordinator worker counts are desired targets, not observations. Runtime
endpoint discovery is the source of truth for active workers, while the
coordinator's decision acknowledgement indicates whether scaling is still
in progress.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/virtual.py#L193)

<h4 id="api-dynamo-planner-connectors-virtual-virtualconnector-get-model-name">
  get_model_name
</h4>

```python
get_model_name(require_prefill: bool = True, require_decode: bool = True) -> str
```

Get the model name from the deployment

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/virtual.py#L250)

<h4 id="api-dynamo-planner-connectors-virtual-virtualconnector-get-gpu-counts">
  get_gpu_counts
</h4>

```python
get_gpu_counts(require_prefill: bool = True, require_decode: bool = True) -> tuple[Optional[int], Optional[int]]
```

Virtual deployments do not expose GPU shape through the coordinator.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/connectors/virtual.py#L256)

#### WorkerCapabilities (class)

Static per-engine capabilities discovered at startup from MDC.

```python
from dynamo.planner.core import WorkerCapabilities
```

```python
WorkerCapabilities(prefill: Optional[EngineCapabilities] = None, decode: Optional[EngineCapabilities] = None) -> None
```

Provided once when constructing the planner core.  In native mode
these come from `WorkerInfo` (resolved via MDC / DGD); in replay
they come from the simulated engine args.

For agg mode, only `decode` is populated (single engine type).

[`components/src/dynamo/planner/core/types.py#L214`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py#L214)

**Public methods**

<h4 id="api-dynamo-planner-core-types-workercapabilities-init">
  **init**
</h4>

```python
__init__(prefill: Optional[EngineCapabilities] = None, decode: Optional[EngineCapabilities] = None) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py)

#### WorkerCounts (class)

Current worker inventory as reported by the adapter.

```python
from dynamo.planner.core import WorkerCounts
```

```python
WorkerCounts(ready_num_prefill: Optional[int] = None, ready_num_decode: Optional[int] = None, expected_num_prefill: Optional[int] = None, expected_num_decode: Optional[int] = None, prefill_scaling_in_progress: bool = False, decode_scaling_in_progress: bool = False) -> None
```

[`components/src/dynamo/planner/core/types.py#L62`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py#L62)

**Public methods**

<h4 id="api-dynamo-planner-core-types-workercounts-init">
  **init**
</h4>

```python
__init__(ready_num_prefill: Optional[int] = None, ready_num_decode: Optional[int] = None, expected_num_prefill: Optional[int] = None, expected_num_decode: Optional[int] = None, prefill_scaling_in_progress: bool = False, decode_scaling_in_progress: bool = False) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/core/types.py)

#### WorkerInfo (class)

Consolidated worker metadata for the planner.

```python
from dynamo.planner import WorkerInfo
```

```python
WorkerInfo(k8s_name: Optional[str] = None, component_name: Optional[str] = None, endpoint: Optional[str] = None, model_name: Optional[str] = None, total_kv_blocks: Optional[int] = None, kv_cache_block_size: Optional[int] = None, max_num_seqs: Optional[int] = None, max_num_batched_tokens: Optional[int] = None, context_length: Optional[int] = None, speculative_nextn: Optional[int] = None) -> None
```

Populated from MDC (DynamoWorkerMetadata CRs) in Kubernetes mode,
with fallback to DGD container-arg parsing, then hard-coded defaults.

[`components/src/dynamo/planner/monitoring/worker_info.py#L26`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/monitoring/worker_info.py#L26)

**Public methods**

<h4 id="api-dynamo-planner-monitoring-worker-info-workerinfo-summary">
  summary
</h4>

```python
summary() -> str
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/monitoring/worker_info.py#L54)

<h4 id="api-dynamo-planner-monitoring-worker-info-workerinfo-init">
  **init**
</h4>

```python
__init__(k8s_name: Optional[str] = None, component_name: Optional[str] = None, endpoint: Optional[str] = None, model_name: Optional[str] = None, total_kv_blocks: Optional[int] = None, kv_cache_block_size: Optional[int] = None, max_num_seqs: Optional[int] = None, max_num_batched_tokens: Optional[int] = None, context_length: Optional[int] = None, speculative_nextn: Optional[int] = None) -> None
```

No summary available.

[source](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/monitoring/worker_info.py)

#### create\_provider (function)

Create the entry-point registered Planner sweep configuration provider.

```python
from dynamo.planner.simulation import create_provider
```

```python
create_provider() -> DynamoPlannerSweepConfigProvider
```

[`components/src/dynamo/planner/simulation/provider.py#L462`](https://github.com/ai-dynamo/dynamo/blob/main/components/src/dynamo/planner/simulation/provider.py#L462)