Skip to content
61 changes: 61 additions & 0 deletions flashdreams/flashdreams/runtime/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Experimental inference runtime API envelope.

This package defines the small v0 boundary above ``flashdreams.infra``. It is
intentionally additive while integrations migrate onto it.
"""

from flashdreams.runtime.config import ExecutionBackend, InferenceConfig, Precision
from flashdreams.runtime.inputs import (
InputField,
ModelInputs,
ModelInputSchema,
TimeWindow,
UserInputEvent,
UserInputs,
UserInputSchema,
)
from flashdreams.runtime.interfaces import (
InferenceRuntime,
InferenceSession,
ModelAdapter,
StepRequest,
StepResult,
)
from flashdreams.runtime.mapping import IdentityInputMapping, InputMapping
from flashdreams.runtime.metrics import (
InMemoryMetricsRecorder,
MetricsRecorder,
NullMetricsRecorder,
RuntimeMetricSample,
)
from flashdreams.runtime.output import NullOutputTarget, OutputArtifact, OutputTarget

__all__ = [
"ExecutionBackend",
"IdentityInputMapping",
"InferenceConfig",
"InferenceRuntime",
"InferenceSession",
"InMemoryMetricsRecorder",
"InputField",
"InputMapping",
"MetricsRecorder",
"ModelAdapter",
"ModelInputs",
"ModelInputSchema",
"NullMetricsRecorder",
"NullOutputTarget",
"OutputArtifact",
"OutputTarget",
"Precision",
"RuntimeMetricSample",
"StepRequest",
"StepResult",
"TimeWindow",
"UserInputEvent",
"UserInputs",
"UserInputSchema",
]
65 changes: 65 additions & 0 deletions flashdreams/flashdreams/runtime/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Runtime-facing configuration envelope."""

from __future__ import annotations

from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Literal, Mapping

ExecutionBackend = Literal["local", "local-distributed", "external", "hosted"]
"""Execution backend families the v0 envelope leaves room for."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should define what each "ENUM" literal means.

Suggested change
"""Execution backend families the v0 envelope leaves room for."""
"""Techniques to host inference compute."""

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

What about ‘Where and how inference compute is run’ rather than ‘host’, since local backends are not hosted services.


Precision = Literal["auto", "fp32", "fp16", "bf16"]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
Precision = Literal["auto", "fp32", "fp16", "bf16"]
class Precision(Enum):
AUTO = "auto"
FP32 = "fp32"
FP16 = "fp16"
BF16 = "bf16"

We should use enum.Enum for all enums, this should make LSP happier.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah there may be an LSP benefit. I’d keep literal for the T1 task and revisit enum when we actually implement this part of the API.

"""Coarse runtime precision choices."""


@dataclass(frozen=True, kw_only=True, slots=True)
class InferenceConfig:
"""Model/runtime execution settings.

Prompts, user controls, browser settings, output paths, and benchmark
directories intentionally live outside this object.
"""

model_id: str
"""Stable model or adapter identity."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
model_id: str
"""Stable model or adapter identity."""
model_id: str
"""Model architecture used to host the selected `checkpoint`."""

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

What about "Stable identity for the model adapter or runtime integration."


preset_id: str | None = None
"""Optional preset identity under :attr:`model_id`."""
Comment on lines +37 to +38

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why is this optional? To identify a model given a YAML we need an identity string to refer to

Suggested change
preset_id: str | None = None
"""Optional preset identity under :attr:`model_id`."""
preset_id: str
"""Unique preset identity"""

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The model_id is defined earlier, which is non-optional, so this would be an optional extra thing, like if you're using the lingbot model, it could have some optional preset things that you could use instead, like a lingbot+wan or lingbot+taev. Unless you think that should not be optional?


checkpoint: str | Path | None = None
"""Optional checkpoint or model-asset selector understood by the adapter."""
Comment on lines +40 to +41

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why is this optional? this would mean we hard-code default checkpoint locations somewhere.

Suggested change
checkpoint: str | Path | None = None
"""Optional checkpoint or model-asset selector understood by the adapter."""
checkpoint: str | Path
"""Checkpoint understood by the adapter. URL to fetch from or Path to local file. Ensure `env` contains `HF_TOKEN` if fetching from hugging-face."""

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I was thinking here that for some models, the checkpoint may just be implicit and the ModelAdapter would be able to handle it just based on the model_id, or that could be overridden by this checkpoint str. But maybe that's wrong and we should just always require this? What do you think?


backend: ExecutionBackend = "local"
"""Runtime backend family."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
backend: ExecutionBackend = "local"
"""Runtime backend family."""
backend: ExecutionBackend = "local"
"""Technique to host inference compute."""

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

What about "Execution placement and backend family for inference compute." instead?


device: str | None = None
"""Optional device selector such as ``cuda`` or ``cuda:0``."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
device: str | None = None
"""Optional device selector such as ``cuda`` or ``cuda:0``."""
device: str = "cuda"
"""Device selector such as ``cuda`` or ``cuda:0``."""

Why does not specifying a device make sense to include?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

device=None lets the adapter/backend choose placement, which might matter for hosted/external runs and existing local configs. Adapters that require explicit placement can reject None in a validate step.


precision: Precision = "auto"
"""Preferred compute precision."""

compile: bool | None = None
"""Whether model compilation is requested, disabled, or left to the adapter."""
Comment thread
jarcherNV marked this conversation as resolved.
Outdated

cuda_graph: bool | None = None
"""Whether CUDA graph capture is requested, disabled, or left to the adapter."""
Comment thread
jarcherNV marked this conversation as resolved.
Outdated

attention_backend: str | None = None
"""Optional attention implementation selector."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
"""Optional attention implementation selector."""
"""Optional - attention implementation selector. `None` means unused."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What're available attention_backend exposed here? Is this field going to be used to choose

        sdpa_backend = {
            "math": torch.nn.attention.SDPBackend.MATH,
            "efficient": torch.nn.attention.SDPBackend.EFFICIENT_ATTENTION,
            "cudnn": torch.nn.attention.SDPBackend.CUDNN_ATTENTION,
            "flash": torch.nn.attention.SDPBackend.FLASH_ATTENTION,
        }[self.backend]

One of the suggestions I have is we remove all these implementation details selector out of InferenceConfig, or we create a ModelConfig class to hold all the implementation details in a model. For now, we can store one ModelConfig per InferenceConfig. Later when we start building auto tune system we can store a list of candidate ModelConfig for the auto tuner to pick.

See Triton autotune system for reference: https://triton-lang.org/main/python-api/generated/triton.autotune.html

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah that probably makes sense. The fields like attention_backend and cache_policy are not really universal inference config and if we keep adding stuff like that then InferenceConfig could probably become bloated pretty quickly. I'll see if I can split this stuff out into a ModelConfig thing.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Regarding the suggested wording change, what about "Optional attention implementation selector; None leaves the choice to the adapter."


cache_policy: str | None = None
"""Optional cache policy selector."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
"""Optional cache policy selector."""
"""Optional - cache policy selector. `None` means unused."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What are some available options here? We should make a Enum instead of str.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah a free string is probably ambiguous if this is a shared field. I'd prefer not to define the canonical cache policies now though, it's probably better to leave that for the T9 task.


runtime_options: Mapping[str, Any] = field(default_factory=dict)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should we use TypedDict over dict for all dictionary? Again, this should make LSP happier.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

For runtime_options/resource_hints, a shared TypedDict would be too generic to help much because the keys are adapter/backend-specific. It's probably better to use adapter-owned typed configs once those shapes are known when we implement them.

"""Adapter/backend-specific runtime options."""

resource_hints: Mapping[str, Any] = field(default_factory=dict)
"""Cheap resource hints for launchers, schedulers, or hosted backends."""
Comment thread
jarcherNV marked this conversation as resolved.
Outdated

def __post_init__(self) -> None:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We likely need more validation on parameter values and checks if types assigned were correct & if elements like runtime_options are valid

maybe we stub these checks?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah that sounds reasonable, I'll see what checks I can add.

if not self.model_id.strip():
raise ValueError("InferenceConfig.model_id must be non-empty.")
144 changes: 144 additions & 0 deletions flashdreams/flashdreams/runtime/inputs.py

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should we split user input and model input into two source files?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah that might make sense. We could probably do that in the T2/T3 tasks, I'll leave that up to whoever works on those tasks to decide.

Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should at some point doc-comment these members in the file to better explain purpose (and add a requirement to CI so that our API does not fall apart over time)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah we should do that at some point before we merge all this stuff to main. I guess once the API is more settled we can throw that in.

# SPDX-License-Identifier: Apache-2.0

"""User- and model-input envelopes for the experimental runtime API."""

from __future__ import annotations

import math
from dataclasses import dataclass, field
from typing import Any, Iterable, Mapping


@dataclass(frozen=True, kw_only=True, slots=True)
class TimeWindow:
"""Half-open time window in canonical seconds."""

start_s: float
end_s: float

def __post_init__(self) -> None:
if not math.isfinite(self.start_s) or not math.isfinite(self.end_s):
raise ValueError("TimeWindow bounds must be finite seconds.")
if self.start_s < 0 or self.end_s < 0:
raise ValueError("TimeWindow bounds must be non-negative.")
if self.end_s < self.start_s:
raise ValueError("TimeWindow.end_s must be >= start_s.")

def contains(self, timestamp_s: float) -> bool:
"""Return whether ``timestamp_s`` falls within this half-open window."""
return self.start_s <= timestamp_s < self.end_s


@dataclass(frozen=True, kw_only=True, slots=True)
class InputField:
"""Lightweight schema field for user snapshots or model inputs."""

name: str
required: bool = True
semantic_type: str | None = None
description: str = ""

def __post_init__(self) -> None:
if not self.name.strip():
raise ValueError("InputField.name must be non-empty.")


@dataclass(frozen=True, kw_only=True, slots=True)
class UserInputSchema:
"""Minimal metadata for controls an app, transport, or trace can provide."""

event_kinds: frozenset[str] = field(default_factory=frozenset)
snapshot_fields: tuple[InputField, ...] = ()
Comment thread
greptile-apps[bot] marked this conversation as resolved.
description: str = ""

def supports_event_kinds(self, kinds: Iterable[str]) -> bool:
"""Return whether every requested event kind is declared supported."""
requested = frozenset(kinds)
if not requested:
return True
return requested.issubset(self.event_kinds)


@dataclass(frozen=True, kw_only=True, slots=True)
class ModelInputSchema:
"""Minimal metadata for model-facing initial and per-step inputs."""

initial_fields: tuple[InputField, ...] = ()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
initial_fields: tuple[InputField, ...] = ()
initial_fields: tuple[InputField, ...] = ()
"""Inputs needed to run first generation."""

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

What about "These are model inputs required before starting the initial generation/session."

step_fields: tuple[InputField, ...] = ()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
step_fields: tuple[InputField, ...] = ()
step_fields: tuple[InputField, ...] = ()
"""Inputs needed to run generation at an arbitrary step after the initial generation."""

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

What about phrasing it as "per-step model inputs required after the session starts."

description: str = ""

def missing_initial(self, inputs: "ModelInputs") -> tuple[str, ...]:
"""Return required initial fields absent from ``inputs``."""
return _missing_required(self.initial_fields, inputs.initial)

def missing_step(self, inputs: "ModelInputs") -> tuple[str, ...]:
"""Return required per-step fields absent from ``inputs``."""
return _missing_required(self.step_fields, inputs.step)

def require_initial(self, inputs: "ModelInputs") -> None:
"""Raise if required initial fields are absent."""
missing = self.missing_initial(inputs)
if missing:
raise ValueError(f"Missing required initial model input(s): {missing}")

def require_step(self, inputs: "ModelInputs") -> None:
"""Raise if required per-step fields are absent."""
missing = self.missing_step(inputs)
if missing:
raise ValueError(f"Missing required step model input(s): {missing}")


@dataclass(frozen=True, kw_only=True, slots=True)
class UserInputEvent:
"""Timestamped user-facing input event."""

timestamp_s: float
kind: str
payload: Mapping[str, Any] = field(default_factory=dict)
source: str | None = None
event_id: str | None = None

@ArielG-NV ArielG-NV Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why string and not int?

also- how do we have no id?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

do we mean event_type here? otherwise sounds hash should just be the id

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

hmm, but we already have event.kind

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, I think part of the confusion is naming. kind is meant to be the event type, e.g. move, look, reset, etc. event_id is not meant to be the primary identity/hash of the event; it is only an optional source/correlation ID from a transport, replay trace, or external system. Many runtime-stamped events will not need one.

Maybe we just rename event_id to something like source_event_id or correlation_id and maybe rename kind to event_type.

What do you guys think?


def __post_init__(self) -> None:
if not math.isfinite(self.timestamp_s) or self.timestamp_s < 0:
raise ValueError("UserInputEvent.timestamp_s must be finite and >= 0.")
if not self.kind.strip():
raise ValueError("UserInputEvent.kind must be non-empty.")


@dataclass(frozen=True, kw_only=True, slots=True)
class UserInputs:
"""Transport-neutral user inputs for live, replayed, synthetic, or no-op runs."""

events: tuple[UserInputEvent, ...] = ()
snapshot: Mapping[str, Any] = field(default_factory=dict)
metadata: Mapping[str, Any] = field(default_factory=dict)

def window(self, time_window: TimeWindow) -> "UserInputs":
"""Return inputs with events filtered to ``time_window``."""
return UserInputs(
events=tuple(
event for event in self.events if time_window.contains(event.timestamp_s)
),
snapshot=self.snapshot,
metadata=self.metadata,
)


@dataclass(frozen=True, kw_only=True, slots=True)
class ModelInputs:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

As commented in flashdreams/flashdreams/runtime/interfaces.py, I'd like a declarative way of defining model inputs. The user should be able to build a Model that expose the input scheme directly. Instead of using a dedicated ModelInput object.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah a declarative Model API could expose its schema directly. I still think we need a transport-neutral ModelInputs payload underneath for mapping, replay, tests, and benchmarks. The later declarative layer can wrap or produce ModelInputs rather than removing that boundary.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

One new issue I found when reviewing this: How is the ModelInputSchema being used to constraint ModelInputs? One thing that confused me a lot is the schema and input are very separated and it feels like it requires a lot of hard coded constraint to validate schema. A good schema should be defined through some kind of typing system and being validated automatically. I suggest we should even look into some existing solutions like Pydantic: https://github.com/pydantic/pydantic

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Design-wise, I agree the current T1 schema is only lightweight field-presence validation. I’ll leave the decision on how to validate up to whoever implements the T2/T3 tasks.

"""Model-facing input payloads split by initial and per-step use."""

initial: Mapping[str, Any] = field(default_factory=dict)
step: Mapping[str, Any] = field(default_factory=dict)
metadata: Mapping[str, Any] = field(default_factory=dict)

def with_step(self, step: Mapping[str, Any]) -> "ModelInputs":
"""Return a copy with replaced per-step payload."""
return ModelInputs(initial=self.initial, step=step, metadata=self.metadata)


def _missing_required(
fields: tuple[InputField, ...], payload: Mapping[str, Any]
) -> tuple[str, ...]:
return tuple(field.name for field in fields if field.required and field.name not in payload)
114 changes: 114 additions & 0 deletions flashdreams/flashdreams/runtime/interfaces.py

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not sure if the current "pipeline" way of interface definition is a good idea or not. This requires users to compose the application in a sequential way. They need to choose the session, an adapter, then a model.

I think a better to structure the application is providing a model interface and a session interface. The model interface specifies model input schema. The session interface specifies user input schemas. The user will implement their Session declaratively. The input mapping happens inside a Session implementation.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah that might be a useful design direction, we should probably compare it before committing T2-T4. My intent for this PR is the lower-level T1 envelope rather than the final user-facing authoring API. I think the current primitives can still sit underneath a declarative model/session API: a model can expose ModelInputSchema, a session can expose UserInputSchema, and the session can own or wrap an InputMapping. I’d prefer not to do a full pivot in this PR until we have the alternative proposal and can check it against LingBot, OmniDreams, the-internal-demo-that-shall-not-be-named and Reactor requirements.

Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Protocols for model adapters, runtimes, and sessions."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any, Mapping, Protocol, runtime_checkable

from flashdreams.runtime.config import InferenceConfig
from flashdreams.runtime.inputs import (
ModelInputs,
ModelInputSchema,
TimeWindow,
UserInputSchema,
)

if TYPE_CHECKING:
from flashdreams.runtime.mapping import InputMapping


@dataclass(frozen=True, kw_only=True, slots=True)
class StepRequest:
"""Model-session request for the next step's inputs."""

step_index: int
model_input_schema: ModelInputSchema | None = None
user_input_window: TimeWindow | None = None
metadata: Mapping[str, Any] = field(default_factory=dict)

def __post_init__(self) -> None:
if self.step_index < 0:
raise ValueError("StepRequest.step_index must be >= 0.")


@dataclass(frozen=True, kw_only=True, slots=True)
class StepResult:
"""Generated output and metadata for one inference step."""

step_index: int
output: Any = None
metadata: Mapping[str, Any] = field(default_factory=dict)
metrics: Mapping[str, float | int] = field(default_factory=dict)

def __post_init__(self) -> None:
if self.step_index < 0:
raise ValueError("StepResult.step_index must be >= 0.")


@runtime_checkable
class InferenceSession(Protocol):
"""One rollout or stream with isolated cache/state."""

def next_step_request(self) -> StepRequest:
"""Describe the model inputs needed for the next call to :meth:`step`."""
...

def step(self, inputs: ModelInputs) -> StepResult:
"""Run one sequential inference step."""
...

def reset(self, inputs: ModelInputs | None = None) -> None:
"""Reset this session's rollout state when the backend supports it."""
...

def close(self) -> None:
"""Release per-session resources."""
...


@runtime_checkable
class InferenceRuntime(Protocol):
"""Heavyweight reusable runtime created from :class:`InferenceConfig`."""

def start_session(self, inputs: ModelInputs) -> InferenceSession:
"""Create an isolated session from initial model inputs."""
...

def close(self) -> None:
"""Release model/backend resources."""
...


@runtime_checkable
class ModelAdapter(Protocol):
"""Model-specific boundary that connects FlashDreams to a model runtime."""

@property
def model_id(self) -> str:
"""Stable model or adapter identity."""
...

@property
def model_input_schema(self) -> ModelInputSchema:
"""Initial and per-step model input requirements."""
...

@property
def user_input_schema(self) -> UserInputSchema | None:
"""User input capabilities this adapter can map directly, if any."""
...

def default_input_mapping(self) -> "InputMapping | None":
"""Return the adapter's default user-to-model input mapping, if any."""
...

def validate_config(self, config: InferenceConfig) -> None:
"""Fail early for unsupported runtime settings."""
...

def create_runtime(self, config: InferenceConfig) -> InferenceRuntime:
"""Initialize and return the heavyweight runtime."""
...
Loading
Loading