Skip to content

Core

steerability.algorithms.core

Core functionality for steering pipelines, control composition, and argument parsing.

base_args

Base argument validation for steering method configuration.

T = TypeVar('T', bound='BaseArgs') module-attribute

BaseArgs dataclass

Base class for all method's args classes.

Source code in steerability/algorithms/core/base_args.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@dataclass
class BaseArgs:
    """Base class for all method's args classes."""

    @classmethod
    def validate(cls: type[T], _init_data: Any | None = None, **kwargs) -> T:
        """Create and validate an Args instance from dict, kwargs, or existing instance.

        Args:
            _init_data: Existing instance, dict of args, or None. Named with underscore prefix
                to avoid collision with common field names like "data".

        Returns:
            Validated instance of the Args class
        """

        if isinstance(_init_data, cls):
            return _init_data

        if isinstance(_init_data, Mapping):
            kwargs = {**_init_data, **kwargs}

        return cls(**kwargs)
validate(_init_data=None, **kwargs) classmethod

Create and validate an Args instance from dict, kwargs, or existing instance.

Parameters:

Name Type Description Default
_init_data Any | None

Existing instance, dict of args, or None. Named with underscore prefix to avoid collision with common field names like "data".

None

Returns:

Type Description
T

Validated instance of the Args class

Source code in steerability/algorithms/core/base_args.py
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@classmethod
def validate(cls: type[T], _init_data: Any | None = None, **kwargs) -> T:
    """Create and validate an Args instance from dict, kwargs, or existing instance.

    Args:
        _init_data: Existing instance, dict of args, or None. Named with underscore prefix
            to avoid collision with common field names like "data".

    Returns:
        Validated instance of the Args class
    """

    if isinstance(_init_data, cls):
        return _init_data

    if isinstance(_init_data, Mapping):
        kwargs = {**_init_data, **kwargs}

    return cls(**kwargs)

base_control

Shared base class for steering controls across all four categories.

BaseControl

Bases: ABC

Common construction and lifecycle for steering controls.

Subclasses set Args to their hyperparameter dataclass; construction validates the arguments and mirrors every field onto the instance. A field whose name the subclass exposes as a @property is not mirrored (e.g. CAST.condition_point); the raw value stays reachable via self.args.<name>. Controls with Args = None accept no constructor arguments.

Attributes:

Name Type Description
Args type[BaseArgs] | None

The control's hyperparameter dataclass, or None for arg-free controls.

RUNTIME_KWARGS_SCHEMA list[dict]

Declarations for the per-call parameters the pipeline maps onto the control at inference time. Each entry is a dict carrying name plus optional type, required, help, and scope fields. scope is "row" for a per-prompt value (in a batched call the control receives a sequence with one element per prompt row, in row order, each element one row's value) or "call" for one value per generate call regardless of batch size; an entry without scope is "call". The pipeline validates the declarations at steer() and raises when two enabled controls declare one name with a different scope or type.

enabled bool

Whether the control participates in the pipeline (identity controls set False).

supports_batching bool

Whether the control processes a batched prompt in one call.

Source code in steerability/algorithms/core/base_control.py
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
class BaseControl(ABC):
    """Common construction and lifecycle for steering controls.

    Subclasses set `Args` to their hyperparameter dataclass; construction validates the arguments
    and mirrors every field onto the instance. A field whose name the subclass exposes as a
    `@property` is not mirrored (e.g. `CAST.condition_point`); the raw value stays reachable via
    `self.args.<name>`. Controls with `Args = None` accept no constructor arguments.

    Attributes:
        Args: The control's hyperparameter dataclass, or None for arg-free controls.
        RUNTIME_KWARGS_SCHEMA: Declarations for the per-call parameters the pipeline maps onto the
            control at inference time. Each entry is a dict carrying `name` plus optional `type`,
            `required`, `help`, and `scope` fields. `scope` is `"row"` for a per-prompt value (in
            a batched call the control receives a sequence with one element per prompt row, in row
            order, each element one row's value) or `"call"` for one value per `generate` call
            regardless of batch size; an entry without `scope` is `"call"`. The pipeline validates
            the declarations at `steer()` and raises when two enabled controls declare one name
            with a different `scope` or `type`.
        enabled: Whether the control participates in the pipeline (identity controls set False).
        supports_batching: Whether the control processes a batched prompt in one call.
    """

    Args: type[BaseArgs] | None = None
    RUNTIME_KWARGS_SCHEMA: list[dict] = []

    enabled: bool = True
    supports_batching: bool = False

    def __init__(self, *args, **kwargs) -> None:
        if self.Args is None:  # null / arg-free control
            if args or kwargs:
                raise TypeError(f"{type(self).__name__} accepts no constructor arguments.")
            self._configure()
            return

        self.args: BaseArgs = self.Args.validate(*args, **kwargs)

        # move fields to attributes, skipping any name the control exposes as a property
        # (e.g. CAST.condition_point); the raw value stays reachable via self.args.<name>
        for field in fields(self.args):
            if isinstance(getattr(type(self), field.name, None), property):
                continue
            setattr(self, field.name, getattr(self.args, field.name))

        self._configure()

    def _configure(self) -> None:
        """Post-construction hook, called after `Args` fields are mirrored onto the instance.

        Driver presets override this to map their mirrored args onto the fields their generic base
        reads, so subclasses never bypass a parent `__init__`. Default no-op.
        """
        pass

    def requirements(self) -> Requirements:
        """Backend requirements computed from this instance's configuration, per phase.

        The default requires `Capability.IN_PROCESS_TORCH` at generate and nothing at score,
        which only the Hugging Face backend satisfies. A control with portable mechanisms
        overrides this to state weaker or alternative requirements. Configuration determines the
        result, so two configurations of one class may differ. Only enabled controls are
        consulted during support evaluation.

        Returns:
            The control's phase-keyed requirements.
        """
        return Requirements(generate=needs(Capability.IN_PROCESS_TORCH))

    def steer_access(self) -> ModelAccess:
        """The model access this instance's steer step requires, on the `ModelAccess` ladder.

        The default is `ModelAccess.FACTS` (layout and tokenizer only). A control whose steer
        step generates or scores through the session declares `ROLLOUTS`, one that captures
        hidden states declares `CAPTURE`, and one that touches the model as a live
        `torch.nn.Module` declares `MODULE`. Configuration determines the result. The pipeline
        hands `steer()` a session scoped to the declared rung, and the live model only at
        `MODULE`. A control may retain the pipeline model beyond `steer()` only if its
        generate phase requires `Capability.IN_PROCESS_TORCH`.

        Returns:
            The declared access rung.
        """
        return ModelAccess.FACTS

    def steer_fits(self) -> tuple[tuple[str, str], ...]:
        """The fit artifacts this instance's steer step will produce, for the steer plan.

        Each entry is `(artifact, artifact_class)`, where `artifact` is the fit source or
        recipe class name and `artifact_class` is `"direction"` or `"calibrated"`. The default
        is an empty tuple (no fits).

        Returns:
            The declared fit artifacts, in declaration order.
        """
        return ()

    def export_state(self) -> dict[str, Any]:
        """Steer-time state to persist when freezing, keyed by logical name.

        Values are typed artifacts (`SteeringVector`, `Probe`, `ProbeSet`, a `Memory`
        implementation, `CheckpointArtifact`, `LoRAArtifact`, `torch.Tensor`, or a `Path` to an
        on-disk product). Must be called after `steer()`. The default returns an empty mapping
        (nothing to persist).

        Returns:
            Mapping from logical name to artifact value.
        """
        return {}

    def frozen_form(self, state: dict[str, Any]) -> tuple[str, dict[str, Any]]:
        """The `(registry method key, constructor kwargs)` of this control's frozen form.

        `state` is the output of `export_state()`; artifact values inside the returned kwargs
        are replaced by store references at encode time. When `steer_fits()` is empty and
        `state` is empty, the recipe is the frozen form and the control's own key and recipe
        args are returned unchanged. A control whose freeze expands into several entries may
        return a list of `(method key, kwargs)` pairs instead.

        Args:
            state: The output of `export_state()`.

        Returns:
            The frozen method key and its constructor kwargs.

        Raises:
            NotFreezableError: If the control produces fits or state but declares no frozen
                form.
        """
        if not state and not self.steer_fits():
            from steerability.algorithms.core.registry import method_key_for

            args = getattr(self, "args", None)
            kwargs = {field.name: getattr(args, field.name) for field in fields(args) if field.init} \
                if args is not None else {}
            return method_key_for(type(self)), kwargs
        raise NotFreezableError(
            f"{type(self).__name__} produces steer-time state but declares no frozen form; "
            "override frozen_form() (and export_state()) to support freezing."
        )

    def fit_identity(self) -> Any | None:
        """The object whose canonical form defines this control's fit digest, or None.

        The digest detects recipe edits that invalidate frozen artifacts, so the returned
        object should cover exactly the inputs a re-fit would consume (training data, fit
        specs) and exclude inert application parameters (strengths, multipliers). The default
        returns None (no fits).

        Returns:
            The fit-identity object, or None.
        """
        return None

    def clone_for_call(self, seed: int | None = None) -> "BaseControl":
        """A configuration-preserving shallow clone for one generation call.

        The clone shares steer-time artifacts (memories, steering vectors, attached tokenizers)
        with the original but has its own attribute namespace, so per-call attribute mutation on
        the clone never races another call using the original. When `seed` is given and the
        control defines `reseed(seed)`, the clone's client-side RNG is re-seeded.

        Args:
            seed: Optional seed forwarded to the clone's `reseed()`.

        Returns:
            The clone.
        """
        clone = copy.copy(self)
        if seed is not None:
            reseed = getattr(clone, "reseed", None)
            if callable(reseed):
                reseed(seed)
        return clone

    def cleanup(self) -> None:
        """Release resources allocated during `steer()`.

        Override in subclasses that allocate GPU memory or other resources during steering. Default
        no-op.
        """
        pass
Args = None class-attribute instance-attribute
RUNTIME_KWARGS_SCHEMA = [] class-attribute instance-attribute
args = self.Args.validate(*args, **kwargs) instance-attribute
enabled = True class-attribute instance-attribute
supports_batching = False class-attribute instance-attribute
cleanup()

Release resources allocated during steer().

Override in subclasses that allocate GPU memory or other resources during steering. Default no-op.

Source code in steerability/algorithms/core/base_control.py
195
196
197
198
199
200
201
def cleanup(self) -> None:
    """Release resources allocated during `steer()`.

    Override in subclasses that allocate GPU memory or other resources during steering. Default
    no-op.
    """
    pass
clone_for_call(seed=None)

A configuration-preserving shallow clone for one generation call.

The clone shares steer-time artifacts (memories, steering vectors, attached tokenizers) with the original but has its own attribute namespace, so per-call attribute mutation on the clone never races another call using the original. When seed is given and the control defines reseed(seed), the clone's client-side RNG is re-seeded.

Parameters:

Name Type Description Default
seed int | None

Optional seed forwarded to the clone's reseed().

None

Returns:

Type Description
BaseControl

The clone.

Source code in steerability/algorithms/core/base_control.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
def clone_for_call(self, seed: int | None = None) -> "BaseControl":
    """A configuration-preserving shallow clone for one generation call.

    The clone shares steer-time artifacts (memories, steering vectors, attached tokenizers)
    with the original but has its own attribute namespace, so per-call attribute mutation on
    the clone never races another call using the original. When `seed` is given and the
    control defines `reseed(seed)`, the clone's client-side RNG is re-seeded.

    Args:
        seed: Optional seed forwarded to the clone's `reseed()`.

    Returns:
        The clone.
    """
    clone = copy.copy(self)
    if seed is not None:
        reseed = getattr(clone, "reseed", None)
        if callable(reseed):
            reseed(seed)
    return clone
export_state()

Steer-time state to persist when freezing, keyed by logical name.

Values are typed artifacts (SteeringVector, Probe, ProbeSet, a Memory implementation, CheckpointArtifact, LoRAArtifact, torch.Tensor, or a Path to an on-disk product). Must be called after steer(). The default returns an empty mapping (nothing to persist).

Returns:

Type Description
dict[str, Any]

Mapping from logical name to artifact value.

Source code in steerability/algorithms/core/base_control.py
117
118
119
120
121
122
123
124
125
126
127
128
def export_state(self) -> dict[str, Any]:
    """Steer-time state to persist when freezing, keyed by logical name.

    Values are typed artifacts (`SteeringVector`, `Probe`, `ProbeSet`, a `Memory`
    implementation, `CheckpointArtifact`, `LoRAArtifact`, `torch.Tensor`, or a `Path` to an
    on-disk product). Must be called after `steer()`. The default returns an empty mapping
    (nothing to persist).

    Returns:
        Mapping from logical name to artifact value.
    """
    return {}
fit_identity()

The object whose canonical form defines this control's fit digest, or None.

The digest detects recipe edits that invalidate frozen artifacts, so the returned object should cover exactly the inputs a re-fit would consume (training data, fit specs) and exclude inert application parameters (strengths, multipliers). The default returns None (no fits).

Returns:

Type Description
Any | None

The fit-identity object, or None.

Source code in steerability/algorithms/core/base_control.py
161
162
163
164
165
166
167
168
169
170
171
172
def fit_identity(self) -> Any | None:
    """The object whose canonical form defines this control's fit digest, or None.

    The digest detects recipe edits that invalidate frozen artifacts, so the returned
    object should cover exactly the inputs a re-fit would consume (training data, fit
    specs) and exclude inert application parameters (strengths, multipliers). The default
    returns None (no fits).

    Returns:
        The fit-identity object, or None.
    """
    return None
frozen_form(state)

The (registry method key, constructor kwargs) of this control's frozen form.

state is the output of export_state(); artifact values inside the returned kwargs are replaced by store references at encode time. When steer_fits() is empty and state is empty, the recipe is the frozen form and the control's own key and recipe args are returned unchanged. A control whose freeze expands into several entries may return a list of (method key, kwargs) pairs instead.

Parameters:

Name Type Description Default
state dict[str, Any]

The output of export_state().

required

Returns:

Type Description
tuple[str, dict[str, Any]]

The frozen method key and its constructor kwargs.

Raises:

Type Description
NotFreezableError

If the control produces fits or state but declares no frozen form.

Source code in steerability/algorithms/core/base_control.py
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
def frozen_form(self, state: dict[str, Any]) -> tuple[str, dict[str, Any]]:
    """The `(registry method key, constructor kwargs)` of this control's frozen form.

    `state` is the output of `export_state()`; artifact values inside the returned kwargs
    are replaced by store references at encode time. When `steer_fits()` is empty and
    `state` is empty, the recipe is the frozen form and the control's own key and recipe
    args are returned unchanged. A control whose freeze expands into several entries may
    return a list of `(method key, kwargs)` pairs instead.

    Args:
        state: The output of `export_state()`.

    Returns:
        The frozen method key and its constructor kwargs.

    Raises:
        NotFreezableError: If the control produces fits or state but declares no frozen
            form.
    """
    if not state and not self.steer_fits():
        from steerability.algorithms.core.registry import method_key_for

        args = getattr(self, "args", None)
        kwargs = {field.name: getattr(args, field.name) for field in fields(args) if field.init} \
            if args is not None else {}
        return method_key_for(type(self)), kwargs
    raise NotFreezableError(
        f"{type(self).__name__} produces steer-time state but declares no frozen form; "
        "override frozen_form() (and export_state()) to support freezing."
    )
requirements()

Backend requirements computed from this instance's configuration, per phase.

The default requires Capability.IN_PROCESS_TORCH at generate and nothing at score, which only the Hugging Face backend satisfies. A control with portable mechanisms overrides this to state weaker or alternative requirements. Configuration determines the result, so two configurations of one class may differ. Only enabled controls are consulted during support evaluation.

Returns:

Type Description
Requirements

The control's phase-keyed requirements.

Source code in steerability/algorithms/core/base_control.py
75
76
77
78
79
80
81
82
83
84
85
86
87
def requirements(self) -> Requirements:
    """Backend requirements computed from this instance's configuration, per phase.

    The default requires `Capability.IN_PROCESS_TORCH` at generate and nothing at score,
    which only the Hugging Face backend satisfies. A control with portable mechanisms
    overrides this to state weaker or alternative requirements. Configuration determines the
    result, so two configurations of one class may differ. Only enabled controls are
    consulted during support evaluation.

    Returns:
        The control's phase-keyed requirements.
    """
    return Requirements(generate=needs(Capability.IN_PROCESS_TORCH))
steer_access()

The model access this instance's steer step requires, on the ModelAccess ladder.

The default is ModelAccess.FACTS (layout and tokenizer only). A control whose steer step generates or scores through the session declares ROLLOUTS, one that captures hidden states declares CAPTURE, and one that touches the model as a live torch.nn.Module declares MODULE. Configuration determines the result. The pipeline hands steer() a session scoped to the declared rung, and the live model only at MODULE. A control may retain the pipeline model beyond steer() only if its generate phase requires Capability.IN_PROCESS_TORCH.

Returns:

Type Description
ModelAccess

The declared access rung.

Source code in steerability/algorithms/core/base_control.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
def steer_access(self) -> ModelAccess:
    """The model access this instance's steer step requires, on the `ModelAccess` ladder.

    The default is `ModelAccess.FACTS` (layout and tokenizer only). A control whose steer
    step generates or scores through the session declares `ROLLOUTS`, one that captures
    hidden states declares `CAPTURE`, and one that touches the model as a live
    `torch.nn.Module` declares `MODULE`. Configuration determines the result. The pipeline
    hands `steer()` a session scoped to the declared rung, and the live model only at
    `MODULE`. A control may retain the pipeline model beyond `steer()` only if its
    generate phase requires `Capability.IN_PROCESS_TORCH`.

    Returns:
        The declared access rung.
    """
    return ModelAccess.FACTS
steer_fits()

The fit artifacts this instance's steer step will produce, for the steer plan.

Each entry is (artifact, artifact_class), where artifact is the fit source or recipe class name and artifact_class is "direction" or "calibrated". The default is an empty tuple (no fits).

Returns:

Type Description
tuple[tuple[str, str], ...]

The declared fit artifacts, in declaration order.

Source code in steerability/algorithms/core/base_control.py
105
106
107
108
109
110
111
112
113
114
115
def steer_fits(self) -> tuple[tuple[str, str], ...]:
    """The fit artifacts this instance's steer step will produce, for the steer plan.

    Each entry is `(artifact, artifact_class)`, where `artifact` is the fit source or
    recipe class name and `artifact_class` is `"direction"` or `"calibrated"`. The default
    is an empty tuple (no fits).

    Returns:
        The declared fit artifacts, in declaration order.
    """
    return ()

NotFreezableError

Bases: RuntimeError

A control produces steer-time state but declares no frozen form.

Raised by BaseControl.frozen_form when a control's steer step produces fits or exported state and the control does not override frozen_form to name a constructor-valid frozen form. Re-exported from steerability.spipe.errors alongside the other spipe exceptions.

Source code in steerability/algorithms/core/base_control.py
12
13
14
15
16
17
18
class NotFreezableError(RuntimeError):
    """A control produces steer-time state but declares no frozen form.

    Raised by `BaseControl.frozen_form` when a control's steer step produces fits or exported
    state and the control does not override `frozen_form` to name a constructor-valid frozen
    form. Re-exported from `steerability.spipe.errors` alongside the other spipe exceptions.
    """

execution

Execution seam types for multi-backend steering.

A Backend owns identity, capability advertisement, and session creation; a SteeringSession is the scope within which steering is in force and the unit of concurrency. The pipeline interacts with backends through these two interfaces. Backend implementations live in steerability.backends; this package holds every seam type and imports nothing from steerability.backends at module level.

Artifact = ModelArtifact | CheckpointArtifact | LoRAArtifact module-attribute

OutputControlEntry = StackEntry | ProcessorSpecEntry | ConstraintEntry module-attribute

StateControlEntry = HookEntry | InterventionEntry module-attribute

Alternative dataclass

One way to satisfy a phase requirement, i.e., a conjunction of capability atoms with optional kind predicates over the backend's advertised kind sets.

Attributes:

Name Type Description
atoms frozenset[Capability]

Capability atoms that must all be advertised.

kinds tuple[KindSet, ...]

Kind sets whose names must all be contained in the backend's advertisement of the corresponding kind-set type.

hint str | None

Optional fix text used in unsupported-verdict messages in place of the default.

Source code in steerability/algorithms/core/execution/contracts.py
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
@dataclass(frozen=True, slots=True)
class Alternative:
    """One way to satisfy a phase requirement, i.e., a conjunction of capability atoms with
    optional kind predicates over the backend's advertised kind sets.

    Attributes:
        atoms: Capability atoms that must all be advertised.
        kinds: Kind sets whose names must all be contained in the backend's advertisement of the
            corresponding kind-set type.
        hint: Optional fix text used in unsupported-verdict messages in place of the default.
    """

    atoms: frozenset[Capability] = frozenset()
    kinds: tuple[KindSet, ...] = ()
    hint: str | None = None

    def satisfied_by(self, capabilities: BackendCapabilities) -> bool:
        """Return True when every atom is advertised and every kind set is contained."""
        if not self.atoms <= capabilities.atoms:
            return False
        for kind_set in self.kinds:
            advertised = _advertised_for(kind_set, capabilities)
            if advertised is None or not advertised.contains(kind_set):
                return False
        return True

    def missing(self, capabilities: BackendCapabilities) -> list[str]:
        """Names of the atoms and kind sets this alternative needs but `capabilities` lacks."""
        gaps = [atom.name for atom in sorted(self.atoms - capabilities.atoms, key=lambda a: a.name)]
        for kind_set in self.kinds:
            advertised = _advertised_for(kind_set, capabilities)
            if advertised is None or not advertised.contains(kind_set):
                gaps.append(f"{type(kind_set).__name__}({_kind_names(kind_set)})")
        return gaps
atoms = frozenset() class-attribute instance-attribute
hint = None class-attribute instance-attribute
kinds = () class-attribute instance-attribute
missing(capabilities)

Names of the atoms and kind sets this alternative needs but capabilities lacks.

Source code in steerability/algorithms/core/execution/contracts.py
205
206
207
208
209
210
211
212
def missing(self, capabilities: BackendCapabilities) -> list[str]:
    """Names of the atoms and kind sets this alternative needs but `capabilities` lacks."""
    gaps = [atom.name for atom in sorted(self.atoms - capabilities.atoms, key=lambda a: a.name)]
    for kind_set in self.kinds:
        advertised = _advertised_for(kind_set, capabilities)
        if advertised is None or not advertised.contains(kind_set):
            gaps.append(f"{type(kind_set).__name__}({_kind_names(kind_set)})")
    return gaps
satisfied_by(capabilities)

Return True when every atom is advertised and every kind set is contained.

Source code in steerability/algorithms/core/execution/contracts.py
195
196
197
198
199
200
201
202
203
def satisfied_by(self, capabilities: BackendCapabilities) -> bool:
    """Return True when every atom is advertised and every kind set is contained."""
    if not self.atoms <= capabilities.atoms:
        return False
    for kind_set in self.kinds:
        advertised = _advertised_for(kind_set, capabilities)
        if advertised is None or not advertised.contains(kind_set):
            return False
    return True

ArtifactProvenance dataclass

Identity of the side that produced an artifact.

Attributes:

Name Type Description
backend_spec_hash str | None

BackendSpec.spec_hash of the producing backend.

model_fingerprint str | None

Fingerprint of the producing model.

tokenizer_fingerprint str | None

Fingerprint of the producing tokenizer and chat template.

Source code in steerability/algorithms/core/execution/payloads.py
112
113
114
115
116
117
118
119
120
121
122
123
124
@dataclass(frozen=True, slots=True)
class ArtifactProvenance:
    """Identity of the side that produced an artifact.

    Attributes:
        backend_spec_hash: `BackendSpec.spec_hash` of the producing backend.
        model_fingerprint: Fingerprint of the producing model.
        tokenizer_fingerprint: Fingerprint of the producing tokenizer and chat template.
    """

    backend_spec_hash: str | None = None
    model_fingerprint: str | None = None
    tokenizer_fingerprint: str | None = None
backend_spec_hash = None class-attribute instance-attribute
model_fingerprint = None class-attribute instance-attribute
tokenizer_fingerprint = None class-attribute instance-attribute

Backend

Bases: ABC

A backend owns a loaded model, engine, or connection pool and its lifecycle, advertises capabilities, and creates sessions.

Long-lived consumers hold backends in a cache keyed by BackendSpec so configurations differing only in per-request steering share one resource.

Attributes:

Name Type Description
spec BackendSpec

The frozen identity of this backend configuration.

Source code in steerability/algorithms/core/execution/backend.py
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
class Backend(ABC):
    """A backend owns a loaded model, engine, or connection pool and its lifecycle, advertises
    capabilities, and creates sessions.

    Long-lived consumers hold backends in a cache keyed by `BackendSpec` so configurations
    differing only in per-request steering share one resource.

    Attributes:
        spec: The frozen identity of this backend configuration.
    """

    spec: BackendSpec

    @classmethod
    @abstractmethod
    def capabilities_for_spec(cls, spec: BackendSpec) -> BackendCapabilities:
        """The capability advertisement implied by `spec`, computable without constructing the
        backend. Constructed backends advertise the same sets, verified against the live
        resource where a discovery surface exists."""

    @abstractmethod
    def open_session(self) -> SteeringSession:
        """Open a session for one logical operation."""

    @property
    def capabilities(self) -> frozenset[Capability]:
        """The advertised capability atoms."""
        return self.capabilities_for_spec(self.spec).atoms

    @property
    def intervention_kinds(self) -> InterventionKinds | None:
        """The advertised intervention kinds, when `Capability.INTERVENTION_SPECS` is present."""
        return self.capabilities_for_spec(self.spec).intervention_kinds

    @property
    def processor_kinds(self) -> ProcessorKinds | None:
        """The advertised processor kinds, when `Capability.PER_STEP_LOGIT_SPECS` is present."""
        return self.capabilities_for_spec(self.spec).processor_kinds

    @property
    def capture_kinds(self) -> CaptureKinds | None:
        """The advertised capture kinds, when `Capability.HIDDEN_CAPTURE` is present."""
        return self.capabilities_for_spec(self.spec).capture_kinds

    def stage_artifacts(self, payloads: dict[str, dict[str, torch.Tensor]]) -> None:
        """Make each content-addressed artifact available to the execution side.

        Called by the pipeline at the end of `steer()` with the tensor payloads of every
        lowered intervention spec, keyed by content-addressed artifact id. Staging is
        idempotent: an artifact that already exists at the destination is success. The
        in-process backend keeps live tensors and needs no staging; engine-backed backends
        write into the registry the serving engine reads.

        Args:
            payloads: Mapping from artifact id to a name-to-tensor mapping.
        """
        return None

    def release(self) -> None:
        """Free the resources this backend owns beyond what the caller owns.

        The default is a no-op. Engine-owning backends override this to shut their engines down
        deterministically. Release is idempotent.
        """
        return None
capabilities property

The advertised capability atoms.

capture_kinds property

The advertised capture kinds, when Capability.HIDDEN_CAPTURE is present.

intervention_kinds property

The advertised intervention kinds, when Capability.INTERVENTION_SPECS is present.

processor_kinds property

The advertised processor kinds, when Capability.PER_STEP_LOGIT_SPECS is present.

spec instance-attribute
capabilities_for_spec(spec) abstractmethod classmethod

The capability advertisement implied by spec, computable without constructing the backend. Constructed backends advertise the same sets, verified against the live resource where a discovery surface exists.

Source code in steerability/algorithms/core/execution/backend.py
159
160
161
162
163
164
@classmethod
@abstractmethod
def capabilities_for_spec(cls, spec: BackendSpec) -> BackendCapabilities:
    """The capability advertisement implied by `spec`, computable without constructing the
    backend. Constructed backends advertise the same sets, verified against the live
    resource where a discovery surface exists."""
open_session() abstractmethod

Open a session for one logical operation.

Source code in steerability/algorithms/core/execution/backend.py
166
167
168
@abstractmethod
def open_session(self) -> SteeringSession:
    """Open a session for one logical operation."""
release()

Free the resources this backend owns beyond what the caller owns.

The default is a no-op. Engine-owning backends override this to shut their engines down deterministically. Release is idempotent.

Source code in steerability/algorithms/core/execution/backend.py
204
205
206
207
208
209
210
def release(self) -> None:
    """Free the resources this backend owns beyond what the caller owns.

    The default is a no-op. Engine-owning backends override this to shut their engines down
    deterministically. Release is idempotent.
    """
    return None
stage_artifacts(payloads)

Make each content-addressed artifact available to the execution side.

Called by the pipeline at the end of steer() with the tensor payloads of every lowered intervention spec, keyed by content-addressed artifact id. Staging is idempotent: an artifact that already exists at the destination is success. The in-process backend keeps live tensors and needs no staging; engine-backed backends write into the registry the serving engine reads.

Parameters:

Name Type Description Default
payloads dict[str, dict[str, Tensor]]

Mapping from artifact id to a name-to-tensor mapping.

required
Source code in steerability/algorithms/core/execution/backend.py
190
191
192
193
194
195
196
197
198
199
200
201
202
def stage_artifacts(self, payloads: dict[str, dict[str, torch.Tensor]]) -> None:
    """Make each content-addressed artifact available to the execution side.

    Called by the pipeline at the end of `steer()` with the tensor payloads of every
    lowered intervention spec, keyed by content-addressed artifact id. Staging is
    idempotent: an artifact that already exists at the destination is success. The
    in-process backend keeps live tensors and needs no staging; engine-backed backends
    write into the registry the serving engine reads.

    Args:
        payloads: Mapping from artifact id to a name-to-tensor mapping.
    """
    return None

BackendCapabilities dataclass

A backend's full capability advertisement: atoms plus negotiated kind sets.

Attributes:

Name Type Description
atoms frozenset[Capability]

The advertised Capability atoms.

intervention_kinds InterventionKinds | None

Advertised intervention kinds, present when Capability.INTERVENTION_SPECS is among the atoms.

processor_kinds ProcessorKinds | None

Advertised processor kinds, present when Capability.PER_STEP_LOGIT_SPECS is among the atoms.

capture_kinds CaptureKinds | None

Advertised capture kinds, present when Capability.HIDDEN_CAPTURE is among the atoms.

constraint_kinds ConstraintKinds | None

Advertised constrained-decoding kinds, present when Capability.GUIDED_DECODING is among the atoms.

Source code in steerability/algorithms/core/execution/contracts.py
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
@dataclass(frozen=True, slots=True)
class BackendCapabilities:
    """A backend's full capability advertisement: atoms plus negotiated kind sets.

    Attributes:
        atoms: The advertised `Capability` atoms.
        intervention_kinds: Advertised intervention kinds, present when
            `Capability.INTERVENTION_SPECS` is among the atoms.
        processor_kinds: Advertised processor kinds, present when
            `Capability.PER_STEP_LOGIT_SPECS` is among the atoms.
        capture_kinds: Advertised capture kinds, present when `Capability.HIDDEN_CAPTURE` is
            among the atoms.
        constraint_kinds: Advertised constrained-decoding kinds, present when
            `Capability.GUIDED_DECODING` is among the atoms.
    """

    atoms: frozenset[Capability] = frozenset()
    intervention_kinds: InterventionKinds | None = None
    processor_kinds: ProcessorKinds | None = None
    capture_kinds: CaptureKinds | None = None
    constraint_kinds: ConstraintKinds | None = None
atoms = frozenset() class-attribute instance-attribute
capture_kinds = None class-attribute instance-attribute
constraint_kinds = None class-attribute instance-attribute
intervention_kinds = None class-attribute instance-attribute
processor_kinds = None class-attribute instance-attribute

BackendSpec dataclass

Frozen, hashable identity of one backend configuration.

The spec hash is the backend identity used for engine caching, benchmark checkpoint keys, capability-probe caches, and artifact provenance. Options are canonicalized at construction (nested mappings stored as sorted tuples, dtypes as strings, no live objects), so two specs built from equal option mappings compare and hash equal regardless of key order. Equality and hash() follow spec_hash, so value type is part of identity (an option value of True and one of 1 yield different specs).

Construction also validates the configuration. A "vllm"/"vllm-serve" spec with the vLLM-Hook plugin active (hook_plugin option) and speculative decoding configured (speculative_config option, top-level or under engine_kwargs) is rejected, since draft-model forwards are unhooked and verification passes break the worker's per-request position accounting. A "vllm"/"vllm-serve" spec naming an encoder-decoder model is rejected when the model config resolves locally (encoder-decoder execution is in-process only); an unresolvable reference passes here and is re-checked at backend construction.

Attributes:

Name Type Description
kind str

Backend kind, one of "huggingface", "vllm", or "vllm-serve".

model str | None

Model reference (hub id or local path), or None when the backend adopts an already-loaded model.

options Any

Canonicalized option mapping, stored as sorted tuples.

Raises:

Type Description
ValueError

If kind is unknown, a vLLM spec combines the vLLM-Hook plugin with speculative decoding, or a vLLM spec names a locally resolvable encoder-decoder model.

TypeError

If options is neither a mapping nor a canonical options tuple.

Source code in steerability/algorithms/core/execution/spec.py
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
@dataclass(frozen=True, slots=True, eq=False)
class BackendSpec:
    """Frozen, hashable identity of one backend configuration.

    The spec hash is the backend identity used for engine caching, benchmark checkpoint keys,
    capability-probe caches, and artifact provenance. Options are canonicalized at construction
    (nested mappings stored as sorted tuples, dtypes as strings, no live objects), so two specs
    built from equal option mappings compare and hash equal regardless of key order. Equality
    and `hash()` follow `spec_hash`, so value type is part of identity (an option value of
    `True` and one of `1` yield different specs).

    Construction also validates the configuration. A `"vllm"`/`"vllm-serve"` spec with the
    vLLM-Hook plugin active (`hook_plugin` option) and speculative decoding configured
    (`speculative_config` option, top-level or under `engine_kwargs`) is rejected, since
    draft-model forwards are unhooked and verification passes break the worker's per-request
    position accounting. A `"vllm"`/`"vllm-serve"` spec naming an encoder-decoder model is
    rejected when the model config resolves locally (encoder-decoder execution is in-process
    only); an unresolvable reference passes here and is re-checked at backend construction.

    Attributes:
        kind: Backend kind, one of `"huggingface"`, `"vllm"`, or `"vllm-serve"`.
        model: Model reference (hub id or local path), or None when the backend adopts an
            already-loaded model.
        options: Canonicalized option mapping, stored as sorted tuples.

    Raises:
        ValueError: If `kind` is unknown, a vLLM spec combines the vLLM-Hook plugin with
            speculative decoding, or a vLLM spec names a locally resolvable encoder-decoder
            model.
        TypeError: If `options` is neither a mapping nor a canonical options tuple.
    """

    kind: str
    model: str | None = None
    options: Any = field(default=())

    def __post_init__(self) -> None:
        if self.kind not in KNOWN_BACKEND_KINDS:
            raise ValueError(
                f"Unknown backend kind {self.kind!r}; known kinds are {', '.join(KNOWN_BACKEND_KINDS)}."
            )
        if isinstance(self.model, Path):
            object.__setattr__(self, "model", str(self.model))
        raw_options = self.options
        if isinstance(raw_options, Mapping):
            object.__setattr__(self, "options", canonicalize_option_value(raw_options))
        elif raw_options == ():
            object.__setattr__(self, "options", canonicalize_option_value({}))
        elif not (isinstance(raw_options, tuple) and len(raw_options) == 2 and raw_options[0] == _MAPPING_TAG):
            raise TypeError(
                f"options must be a mapping or a canonical options tuple; got "
                f"{type(raw_options).__name__}."
            )

        if self.kind in ("vllm", "vllm-serve"):
            if self.get_option("hook_plugin"):
                speculative = (
                    self.get_option("speculative_config")
                    or self.get_option("engine_kwargs", "speculative_config")
                )
                if speculative:
                    raise ValueError(
                        "Speculative decoding cannot be combined with the vLLM-Hook plugin: "
                        "draft-model forwards are unhooked and verification passes break the "
                        "worker's per-request position accounting."
                    )
                if (
                    self.kind == "vllm"
                    and self.get_option("engine_kwargs", "enforce_eager") is False
                ):
                    raise ValueError(
                        "enforce_eager=False cannot be combined with the vLLM-Hook plugin: "
                        "worker hooks do not run under CUDA-graph replay. Drop the option "
                        "(hook_plugin engines default to eager execution) or disable the plugin."
                    )
            if self.model is not None:
                _reject_encoder_decoder_if_resolvable(
                    self.model, bool(self.get_option("trust_remote_code", default=False)),
                )

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, BackendSpec):
            return NotImplemented
        return self._identity() == other._identity()

    def __hash__(self) -> int:
        return hash(self._identity())

    def _identity(self) -> tuple[str, str | None, str]:
        return (self.kind, self.model, repr(self.options))

    def get_option(self, *path: str, default: Any = None) -> Any:
        """Read one option by key path, rebuilding plain dicts and lists on the way out.

        Args:
            *path: Nested option keys, e.g. `get_option("hf_model_kwargs", "attn_implementation")`.
            default: Value returned when any key along the path is absent.

        Returns:
            The option value with mappings rebuilt as plain dicts and sequences as plain lists,
            or `default`.
        """
        value: Any = self.options
        for key in path:
            if not (isinstance(value, tuple) and len(value) == 2 and value[0] == _MAPPING_TAG):
                return default
            entries = dict(value[1])
            if key not in entries:
                return default
            value = entries[key]
        return _decanonicalize(value)

    def options_dict(self) -> dict[str, Any]:
        """Return the options as a plain nested dict (empty when no options were provided)."""
        rebuilt = _decanonicalize(self.options)
        return rebuilt if isinstance(rebuilt, dict) else {}

    @property
    def spec_hash(self) -> str:
        """A 16-character hex digest over `(kind, model, options)`, consistent with `__eq__`
        and stable across processes for plain-data options."""
        digest = hashlib.sha256(repr(self._identity()).encode("utf-8"))
        return digest.hexdigest()[:16]
kind instance-attribute
model = None class-attribute instance-attribute
options = field(default=()) class-attribute instance-attribute
spec_hash property

A 16-character hex digest over (kind, model, options), consistent with __eq__ and stable across processes for plain-data options.

get_option(*path, default=None)

Read one option by key path, rebuilding plain dicts and lists on the way out.

Parameters:

Name Type Description Default
*path str

Nested option keys, e.g. get_option("hf_model_kwargs", "attn_implementation").

()
default Any

Value returned when any key along the path is absent.

None

Returns:

Type Description
Any

The option value with mappings rebuilt as plain dicts and sequences as plain lists,

Any

or default.

Source code in steerability/algorithms/core/execution/spec.py
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
def get_option(self, *path: str, default: Any = None) -> Any:
    """Read one option by key path, rebuilding plain dicts and lists on the way out.

    Args:
        *path: Nested option keys, e.g. `get_option("hf_model_kwargs", "attn_implementation")`.
        default: Value returned when any key along the path is absent.

    Returns:
        The option value with mappings rebuilt as plain dicts and sequences as plain lists,
        or `default`.
    """
    value: Any = self.options
    for key in path:
        if not (isinstance(value, tuple) and len(value) == 2 and value[0] == _MAPPING_TAG):
            return default
        entries = dict(value[1])
        if key not in entries:
            return default
        value = entries[key]
    return _decanonicalize(value)
options_dict()

Return the options as a plain nested dict (empty when no options were provided).

Source code in steerability/algorithms/core/execution/spec.py
211
212
213
214
def options_dict(self) -> dict[str, Any]:
    """Return the options as a plain nested dict (empty when no options were provided)."""
    rebuilt = _decanonicalize(self.options)
    return rebuilt if isinstance(rebuilt, dict) else {}

Capability

Bases: Enum

Distinguishing capability atoms advertised by backends.

Attributes:

Name Type Description
IN_PROCESS_TORCH

The backend exposes the model as a live torch.nn.Module in the client process, so torch hooks, live logits processors, and direct weight access are available. The name refers to this mechanism rather than to process locality.

INTERVENTION_SPECS

The backend executes activation interventions submitted as InterventionSpec payloads. The Hugging Face backend does not advertise this atom, since torch hooks cover every intervention a spec expresses; requirements state the relationship as alternatives.

PER_STEP_LOGIT_SPECS

The backend hosts per-step logit math submitted as ProcessorSpec payloads.

HIDDEN_CAPTURE

The backend serves hidden-state capture through SteeringSession.capture.

BEAM_PROPOSALS

The backend implements beam-search proposal semantics (num_beams with multiple returned sequences).

SERVE_CHECKPOINT

The backend can serve a checkpoint directory produced elsewhere.

SERVE_LORA

The backend can serve a LoRA adapter produced elsewhere.

GUIDED_DECODING

The backend hosts declarative constrained decoding natively, rendered from a ConstraintSource onto its structured-output request parameters. The Hugging Face backend does not advertise this atom, since the in-process arm serves the constraint class through a client-compiled automaton; requirements state the relationship as alternatives.

Source code in steerability/algorithms/core/execution/contracts.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Capability(Enum):
    """Distinguishing capability atoms advertised by backends.

    Attributes:
        IN_PROCESS_TORCH: The backend exposes the model as a live `torch.nn.Module` in the client
            process, so torch hooks, live logits processors, and direct weight access are
            available. The name refers to this mechanism rather than to process locality.
        INTERVENTION_SPECS: The backend executes activation interventions submitted as
            `InterventionSpec` payloads. The Hugging Face backend does not advertise this atom,
            since torch hooks cover every intervention a spec expresses; requirements state the
            relationship as alternatives.
        PER_STEP_LOGIT_SPECS: The backend hosts per-step logit math submitted as `ProcessorSpec`
            payloads.
        HIDDEN_CAPTURE: The backend serves hidden-state capture through `SteeringSession.capture`.
        BEAM_PROPOSALS: The backend implements beam-search proposal semantics (`num_beams` with
            multiple returned sequences).
        SERVE_CHECKPOINT: The backend can serve a checkpoint directory produced elsewhere.
        SERVE_LORA: The backend can serve a LoRA adapter produced elsewhere.
        GUIDED_DECODING: The backend hosts declarative constrained decoding natively, rendered
            from a `ConstraintSource` onto its structured-output request parameters. The
            Hugging Face backend does not advertise this atom, since the in-process arm serves
            the constraint class through a client-compiled automaton; requirements state the
            relationship as alternatives.
    """

    IN_PROCESS_TORCH = "in_process_torch"
    INTERVENTION_SPECS = "intervention_specs"
    PER_STEP_LOGIT_SPECS = "per_step_logit_specs"
    HIDDEN_CAPTURE = "hidden_capture"
    BEAM_PROPOSALS = "beam_proposals"
    SERVE_CHECKPOINT = "serve_checkpoint"
    SERVE_LORA = "serve_lora"
    GUIDED_DECODING = "guided_decoding"
BEAM_PROPOSALS = 'beam_proposals' class-attribute instance-attribute
GUIDED_DECODING = 'guided_decoding' class-attribute instance-attribute
HIDDEN_CAPTURE = 'hidden_capture' class-attribute instance-attribute
INTERVENTION_SPECS = 'intervention_specs' class-attribute instance-attribute
IN_PROCESS_TORCH = 'in_process_torch' class-attribute instance-attribute
PER_STEP_LOGIT_SPECS = 'per_step_logit_specs' class-attribute instance-attribute
SERVE_CHECKPOINT = 'serve_checkpoint' class-attribute instance-attribute
SERVE_LORA = 'serve_lora' class-attribute instance-attribute

CaptureKinds dataclass

Hidden-state capture forms a backend serves, by permanent wire name.

Attributes:

Name Type Description
kinds frozenset[str]

Capture kinds, e.g. {"residual"}.

locations frozenset[str]

Capture locations, e.g. {"layer_output", "layer_input"}.

modes frozenset[str]

Capture modes, e.g. {"all_tokens", "last_token"}.

Source code in steerability/algorithms/core/execution/contracts.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
@dataclass(frozen=True, slots=True)
class CaptureKinds:
    """Hidden-state capture forms a backend serves, by permanent wire name.

    Attributes:
        kinds: Capture kinds, e.g. `{"residual"}`.
        locations: Capture locations, e.g. `{"layer_output", "layer_input"}`.
        modes: Capture modes, e.g. `{"all_tokens", "last_token"}`.
    """

    kinds: frozenset[str] = frozenset()
    locations: frozenset[str] = frozenset()
    modes: frozenset[str] = frozenset()

    def contains(self, required: "CaptureKinds") -> bool:
        """Return True when every required kind name is advertised."""
        return (
            required.kinds <= self.kinds
            and required.locations <= self.locations
            and required.modes <= self.modes
        )
kinds = frozenset() class-attribute instance-attribute
locations = frozenset() class-attribute instance-attribute
modes = frozenset() class-attribute instance-attribute
contains(required)

Return True when every required kind name is advertised.

Source code in steerability/algorithms/core/execution/contracts.py
124
125
126
127
128
129
130
def contains(self, required: "CaptureKinds") -> bool:
    """Return True when every required kind name is advertised."""
    return (
        required.kinds <= self.kinds
        and required.locations <= self.locations
        and required.modes <= self.modes
    )

CaptureResult dataclass

Hidden states captured by SteeringSession.capture.

Attributes:

Name Type Description
hidden Mapping[int, Tensor]

Tensors keyed by 0-based layer id. Shape [N, T, H] in "all_tokens" mode and [N, H] in "last_token" mode, on CPU, in the model's native dtype.

attention_mask Tensor

Mask of shape [N, T] matching the captured prompts, on CPU.

mode str

The capture mode the tensors were produced under.

location str

The capture location ("layer_output" or "layer_input").

Source code in steerability/algorithms/core/execution/payloads.py
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
@dataclass(frozen=True, slots=True, eq=False)
class CaptureResult:
    """Hidden states captured by `SteeringSession.capture`.

    Attributes:
        hidden: Tensors keyed by 0-based layer id. Shape `[N, T, H]` in `"all_tokens"` mode and
            `[N, H]` in `"last_token"` mode, on CPU, in the model's native dtype.
        attention_mask: Mask of shape `[N, T]` matching the captured prompts, on CPU.
        mode: The capture mode the tensors were produced under.
        location: The capture location (`"layer_output"` or `"layer_input"`).
    """

    hidden: Mapping[int, torch.Tensor]
    attention_mask: torch.Tensor
    mode: str
    location: str
attention_mask instance-attribute
hidden instance-attribute
location instance-attribute
mode instance-attribute

CheckpointArtifact dataclass

A checkpoint directory handed across the role boundary; consuming it requires Capability.SERVE_CHECKPOINT.

Attributes:

Name Type Description
path str

Checkpoint directory path.

provenance ArtifactProvenance

Identity of the producing side.

Source code in steerability/algorithms/core/execution/payloads.py
141
142
143
144
145
146
147
148
149
150
151
152
@dataclass(frozen=True, slots=True)
class CheckpointArtifact:
    """A checkpoint directory handed across the role boundary; consuming it requires
    `Capability.SERVE_CHECKPOINT`.

    Attributes:
        path: Checkpoint directory path.
        provenance: Identity of the producing side.
    """

    path: str
    provenance: ArtifactProvenance = field(default_factory=ArtifactProvenance)
path instance-attribute
provenance = field(default_factory=ArtifactProvenance) class-attribute instance-attribute

ConstraintEntry dataclass

An output control's contribution as a declarative constrained-decoding source.

Consumed by backends advertising Capability.GUIDED_DECODING, rendered onto the engine's native structured-output request parameters in place of the control's live processor.

Attributes:

Name Type Description
source ConstraintSource

The declarative constraint.

Source code in steerability/algorithms/core/execution/payloads.py
508
509
510
511
512
513
514
515
516
517
518
519
@dataclass(frozen=True, slots=True)
class ConstraintEntry:
    """An output control's contribution as a declarative constrained-decoding source.

    Consumed by backends advertising `Capability.GUIDED_DECODING`, rendered onto the engine's
    native structured-output request parameters in place of the control's live processor.

    Attributes:
        source: The declarative constraint.
    """

    source: ConstraintSource
source instance-attribute

ConstraintKinds dataclass

Constrained-decoding kinds a backend hosts natively, by declarative kind name.

The kind set is static per backend version (the engine's structured-output surface needs no discovery), e.g. {"json_schema", "regex", "grammar", "choice"}.

Attributes:

Name Type Description
constraints frozenset[str]

Constraint kind names.

Source code in steerability/algorithms/core/execution/contracts.py
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
@dataclass(frozen=True, slots=True)
class ConstraintKinds:
    """Constrained-decoding kinds a backend hosts natively, by declarative kind name.

    The kind set is static per backend version (the engine's structured-output surface needs no
    discovery), e.g. `{"json_schema", "regex", "grammar", "choice"}`.

    Attributes:
        constraints: Constraint kind names.
    """

    constraints: frozenset[str] = frozenset()

    def contains(self, required: "ConstraintKinds") -> bool:
        """Return True when every required kind name is advertised."""
        return required.constraints <= self.constraints
constraints = frozenset() class-attribute instance-attribute
contains(required)

Return True when every required kind name is advertised.

Source code in steerability/algorithms/core/execution/contracts.py
146
147
148
def contains(self, required: "ConstraintKinds") -> bool:
    """Return True when every required kind name is advertised."""
    return required.constraints <= self.constraints

ConstraintSource dataclass

A declarative constrained-decoding specification.

The portable form of the constraint class: one source renders per execution arm, compiled into a client-side automaton in process and onto the engine's native structured-output request parameters on vLLM backends.

Attributes:

Name Type Description
kind Literal['json_schema', 'regex', 'grammar', 'choice']

The constraint kind: "json_schema", "regex", "grammar" (EBNF), or "choice".

value str | Mapping | Sequence[str]

The constraint payload: a schema string or mapping for "json_schema", a pattern string for "regex", a grammar string for "grammar", or a sequence of candidate strings for "choice".

Source code in steerability/algorithms/core/execution/payloads.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@dataclass(frozen=True, slots=True)
class ConstraintSource:
    """A declarative constrained-decoding specification.

    The portable form of the constraint class: one source renders per execution arm, compiled
    into a client-side automaton in process and onto the engine's native structured-output
    request parameters on vLLM backends.

    Attributes:
        kind: The constraint kind: `"json_schema"`, `"regex"`, `"grammar"` (EBNF), or
            `"choice"`.
        value: The constraint payload: a schema string or mapping for `"json_schema"`, a
            pattern string for `"regex"`, a grammar string for `"grammar"`, or a sequence of
            candidate strings for `"choice"`.
    """

    kind: Literal["json_schema", "regex", "grammar", "choice"]
    value: str | Mapping | Sequence[str]

    def __post_init__(self) -> None:
        if self.kind not in CONSTRAINT_KINDS:
            raise ValueError(
                f"Unknown constraint kind {self.kind!r}; kinds are {', '.join(CONSTRAINT_KINDS)}."
            )
        if self.kind == "json_schema":
            if not isinstance(self.value, (str, Mapping)):
                raise TypeError("A json_schema constraint takes a schema string or mapping.")
        elif self.kind in ("regex", "grammar"):
            if not isinstance(self.value, str):
                raise TypeError(f"A {self.kind} constraint takes a string.")
        else:
            if isinstance(self.value, str) or not isinstance(self.value, Sequence) or not self.value:
                raise TypeError("A choice constraint takes a non-empty sequence of strings.")
            if not all(isinstance(item, str) for item in self.value):
                raise TypeError("A choice constraint takes a non-empty sequence of strings.")
            object.__setattr__(self, "value", tuple(self.value))
kind instance-attribute
value instance-attribute

GenerationItem dataclass

One prompt's unit of generation work.

Input controls have no entry because their contribution is already folded into prompt; structural controls have none because they contribute at steer time through artifacts.

Attributes:

Name Type Description
prompt PreparedPrompt

The prepared prompt.

state_entries tuple[StateControlEntry, ...]

Enabled state controls' contributions, in controls-list order.

output_entries tuple[OutputControlEntry, ...]

Enabled output controls' contributions, in controls-list order.

seed int | None

Per-item sampling seed, or None for unseeded operation.

Source code in steerability/algorithms/core/execution/payloads.py
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
@dataclass(frozen=True, slots=True, eq=False)
class GenerationItem:
    """One prompt's unit of generation work.

    Input controls have no entry because their contribution is already folded into `prompt`;
    structural controls have none because they contribute at steer time through artifacts.

    Attributes:
        prompt: The prepared prompt.
        state_entries: Enabled state controls' contributions, in controls-list order.
        output_entries: Enabled output controls' contributions, in controls-list order.
        seed: Per-item sampling seed, or None for unseeded operation.
    """

    prompt: PreparedPrompt
    state_entries: tuple[StateControlEntry, ...] = ()
    output_entries: tuple[OutputControlEntry, ...] = ()
    seed: int | None = None
output_entries = () class-attribute instance-attribute
prompt instance-attribute
seed = None class-attribute instance-attribute
state_entries = () class-attribute instance-attribute

GenerationParams dataclass

The sampling-facing subset of generation parameters, normalized across backends.

Each backend family owns one rendering rule. In-process, the normalized fields render onto model.generate names and every key in extra passes through untouched. On API backends the normalized table is exhaustive and unmapped parameters raise, so extra is rejected there.

Attributes:

Name Type Description
max_new_tokens int | None

Maximum number of new tokens.

min_new_tokens int | None

Minimum number of new tokens.

temperature float | None

Sampling temperature.

top_p float | None

Nucleus-sampling probability mass.

top_k int | None

Top-k sampling cutoff.

greedy bool | None

True forces greedy decoding, False forces sampling, None leaves the backend default.

n int | None

Number of returned candidates per prompt.

repetition_penalty float | None

Repetition penalty.

seed int | None

Sampling seed. In-process it renders as a fork_rng-scoped manual_seed around the item's decode; on vLLM it maps to the request seed. Sessions derive a distinct per-item seed from this value when an item carries no seed of its own.

seed_scope Literal['item', 'dispatch']

How a call-level seed maps onto the items of one dispatch. "item" derives one seed per item from the operation id and the item index, so an item's stream is independent of its batch-mates; on the in-process backend a multi-item dispatch then decodes one item at a time. "dispatch" derives one seed for the whole dispatch and decodes every item in one batched pass; the call is reproducible as a whole (the same items in the same order under the same seed reproduce), and an individual item is not reproducible independently of batch composition. Ignored when seed is None. An item carrying its own seed is honored as given under either scope. On vLLM backends the scope is inert, since per-request seeds execute inside one engine batch under either value.

stop_strings tuple[str, ...]

Stop strings, composed by the session as stop rules on both backend families. Token ids are returned as generated; the pipeline truncates decoded text at the first stop-string occurrence.

stop_token_ids tuple[int, ...]

Token ids that halt a row once its last generated token is one of them, in addition to the tokenizer's EOS.

extra Mapping[str, Any]

Additional keyword arguments passed through unmapped on the in-process arm. A normalized field always takes precedence over a same-named key in extra.

Raises:

Type Description
ValueError

If min_new_tokens exceeds max_new_tokens when both are set.

Source code in steerability/algorithms/core/execution/params.py
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
@dataclass(frozen=True, slots=True)
class GenerationParams:
    """The sampling-facing subset of generation parameters, normalized across backends.

    Each backend family owns one rendering rule. In-process, the normalized fields render onto
    `model.generate` names and every key in `extra` passes through untouched. On API backends
    the normalized table is exhaustive and unmapped parameters raise, so `extra` is rejected
    there.

    Attributes:
        max_new_tokens: Maximum number of new tokens.
        min_new_tokens: Minimum number of new tokens.
        temperature: Sampling temperature.
        top_p: Nucleus-sampling probability mass.
        top_k: Top-k sampling cutoff.
        greedy: True forces greedy decoding, False forces sampling, None leaves the backend
            default.
        n: Number of returned candidates per prompt.
        repetition_penalty: Repetition penalty.
        seed: Sampling seed. In-process it renders as a `fork_rng`-scoped `manual_seed` around
            the item's decode; on vLLM it maps to the request seed. Sessions derive a distinct
            per-item seed from this value when an item carries no seed of its own.
        seed_scope: How a call-level `seed` maps onto the items of one dispatch. `"item"` derives
            one seed per item from the operation id and the item index, so an item's stream is
            independent of its batch-mates; on the in-process backend a multi-item dispatch then
            decodes one item at a time. `"dispatch"` derives one seed for the whole dispatch and
            decodes every item in one batched pass; the call is reproducible as a whole (the same
            items in the same order under the same seed reproduce), and an individual item is not
            reproducible independently of batch composition. Ignored when `seed` is None. An item
            carrying its own `seed` is honored as given under either scope. On vLLM backends the
            scope is inert, since per-request seeds execute inside one engine batch under either
            value.
        stop_strings: Stop strings, composed by the session as stop rules on both backend
            families. Token ids are returned as generated; the pipeline truncates decoded text
            at the first stop-string occurrence.
        stop_token_ids: Token ids that halt a row once its last generated token is one of them,
            in addition to the tokenizer's EOS.
        extra: Additional keyword arguments passed through unmapped on the in-process arm. A
            normalized field always takes precedence over a same-named key in `extra`.

    Raises:
        ValueError: If `min_new_tokens` exceeds `max_new_tokens` when both are set.
    """

    max_new_tokens: int | None = None
    min_new_tokens: int | None = None
    temperature: float | None = None
    top_p: float | None = None
    top_k: int | None = None
    greedy: bool | None = None
    n: int | None = None
    repetition_penalty: float | None = None
    seed: int | None = None
    seed_scope: Literal["item", "dispatch"] = "item"
    stop_strings: tuple[str, ...] = ()
    stop_token_ids: tuple[int, ...] = ()
    extra: Mapping[str, Any] = field(default_factory=dict)

    def __post_init__(self) -> None:
        if isinstance(self.stop_strings, str):
            object.__setattr__(self, "stop_strings", (self.stop_strings,))
        else:
            object.__setattr__(self, "stop_strings", tuple(self.stop_strings))
        object.__setattr__(self, "stop_token_ids", tuple(int(i) for i in self.stop_token_ids))
        if self.seed_scope not in SEED_SCOPES:
            raise ValueError(f"seed_scope must be one of {SEED_SCOPES}; got {self.seed_scope!r}.")
        if (
            self.min_new_tokens is not None
            and self.max_new_tokens is not None
            and self.min_new_tokens > self.max_new_tokens
        ):
            raise ValueError(
                f"min_new_tokens={self.min_new_tokens} exceeds max_new_tokens={self.max_new_tokens}; the length "
                "bounds are jointly unsatisfiable. Control contributions only tighten bounds, so lower "
                "min_new_tokens or loosen the tightened max_new_tokens."
            )

    @classmethod
    def from_gen_kwargs(cls, **gen_kwargs: Any) -> "GenerationParams":
        """Split keyword arguments into normalized fields and pass-through extras.

        `do_sample` maps onto `greedy` (inverted) and `num_return_sequences` onto `n`; keys named
        exactly like a normalized field bind to it; everything else lands in `extra`.

        Args:
            **gen_kwargs: Generation keyword arguments in `model.generate` vocabulary.

        Returns:
            The normalized `GenerationParams`.
        """
        normalized: dict[str, Any] = {}
        if "do_sample" in gen_kwargs:
            normalized["greedy"] = not gen_kwargs.pop("do_sample")
        if "num_return_sequences" in gen_kwargs:
            normalized["n"] = gen_kwargs.pop("num_return_sequences")
        for name in NORMALIZED_PARAM_NAMES:
            if name in gen_kwargs:
                normalized[name] = gen_kwargs.pop(name)
        return cls(**normalized, extra=gen_kwargs)

    def to_gen_kwargs(self) -> dict[str, Any]:
        """Render the parameters back into `model.generate`-vocabulary keyword arguments.

        This inverts `from_gen_kwargs`, so `greedy` renders as `do_sample` (inverted), `n` as
        `num_return_sequences`, the stop fields and `seed` keep their normalized names,
        `seed_scope` renders only when it is not the default `"item"`, and `extra` merges
        underneath the normalized fields.

        Returns:
            The keyword arguments; `from_gen_kwargs(**params.to_gen_kwargs())` reproduces
            `params`.
        """
        gen_kwargs: dict[str, Any] = dict(self.extra)
        if self.max_new_tokens is not None:
            gen_kwargs["max_new_tokens"] = self.max_new_tokens
        if self.min_new_tokens is not None:
            gen_kwargs["min_new_tokens"] = self.min_new_tokens
        if self.temperature is not None:
            gen_kwargs["temperature"] = self.temperature
        if self.top_p is not None:
            gen_kwargs["top_p"] = self.top_p
        if self.top_k is not None:
            gen_kwargs["top_k"] = self.top_k
        if self.greedy is not None:
            gen_kwargs["do_sample"] = not self.greedy
        if self.n is not None:
            gen_kwargs["num_return_sequences"] = self.n
        if self.repetition_penalty is not None:
            gen_kwargs["repetition_penalty"] = self.repetition_penalty
        if self.seed is not None:
            gen_kwargs["seed"] = self.seed
        if self.seed_scope != "item":
            gen_kwargs["seed_scope"] = self.seed_scope
        if self.stop_strings:
            gen_kwargs["stop_strings"] = self.stop_strings
        if self.stop_token_ids:
            gen_kwargs["stop_token_ids"] = self.stop_token_ids
        return gen_kwargs
extra = field(default_factory=dict) class-attribute instance-attribute
greedy = None class-attribute instance-attribute
max_new_tokens = None class-attribute instance-attribute
min_new_tokens = None class-attribute instance-attribute
n = None class-attribute instance-attribute
repetition_penalty = None class-attribute instance-attribute
seed = None class-attribute instance-attribute
seed_scope = 'item' class-attribute instance-attribute
stop_strings = () class-attribute instance-attribute
stop_token_ids = () class-attribute instance-attribute
temperature = None class-attribute instance-attribute
top_k = None class-attribute instance-attribute
top_p = None class-attribute instance-attribute
from_gen_kwargs(**gen_kwargs) classmethod

Split keyword arguments into normalized fields and pass-through extras.

do_sample maps onto greedy (inverted) and num_return_sequences onto n; keys named exactly like a normalized field bind to it; everything else lands in extra.

Parameters:

Name Type Description Default
**gen_kwargs Any

Generation keyword arguments in model.generate vocabulary.

{}

Returns:

Type Description
GenerationParams

The normalized GenerationParams.

Source code in steerability/algorithms/core/execution/params.py
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
@classmethod
def from_gen_kwargs(cls, **gen_kwargs: Any) -> "GenerationParams":
    """Split keyword arguments into normalized fields and pass-through extras.

    `do_sample` maps onto `greedy` (inverted) and `num_return_sequences` onto `n`; keys named
    exactly like a normalized field bind to it; everything else lands in `extra`.

    Args:
        **gen_kwargs: Generation keyword arguments in `model.generate` vocabulary.

    Returns:
        The normalized `GenerationParams`.
    """
    normalized: dict[str, Any] = {}
    if "do_sample" in gen_kwargs:
        normalized["greedy"] = not gen_kwargs.pop("do_sample")
    if "num_return_sequences" in gen_kwargs:
        normalized["n"] = gen_kwargs.pop("num_return_sequences")
    for name in NORMALIZED_PARAM_NAMES:
        if name in gen_kwargs:
            normalized[name] = gen_kwargs.pop(name)
    return cls(**normalized, extra=gen_kwargs)
to_gen_kwargs()

Render the parameters back into model.generate-vocabulary keyword arguments.

This inverts from_gen_kwargs, so greedy renders as do_sample (inverted), n as num_return_sequences, the stop fields and seed keep their normalized names, seed_scope renders only when it is not the default "item", and extra merges underneath the normalized fields.

Returns:

Type Description
dict[str, Any]

The keyword arguments; from_gen_kwargs(**params.to_gen_kwargs()) reproduces

dict[str, Any]

params.

Source code in steerability/algorithms/core/execution/params.py
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
def to_gen_kwargs(self) -> dict[str, Any]:
    """Render the parameters back into `model.generate`-vocabulary keyword arguments.

    This inverts `from_gen_kwargs`, so `greedy` renders as `do_sample` (inverted), `n` as
    `num_return_sequences`, the stop fields and `seed` keep their normalized names,
    `seed_scope` renders only when it is not the default `"item"`, and `extra` merges
    underneath the normalized fields.

    Returns:
        The keyword arguments; `from_gen_kwargs(**params.to_gen_kwargs())` reproduces
        `params`.
    """
    gen_kwargs: dict[str, Any] = dict(self.extra)
    if self.max_new_tokens is not None:
        gen_kwargs["max_new_tokens"] = self.max_new_tokens
    if self.min_new_tokens is not None:
        gen_kwargs["min_new_tokens"] = self.min_new_tokens
    if self.temperature is not None:
        gen_kwargs["temperature"] = self.temperature
    if self.top_p is not None:
        gen_kwargs["top_p"] = self.top_p
    if self.top_k is not None:
        gen_kwargs["top_k"] = self.top_k
    if self.greedy is not None:
        gen_kwargs["do_sample"] = not self.greedy
    if self.n is not None:
        gen_kwargs["num_return_sequences"] = self.n
    if self.repetition_penalty is not None:
        gen_kwargs["repetition_penalty"] = self.repetition_penalty
    if self.seed is not None:
        gen_kwargs["seed"] = self.seed
    if self.seed_scope != "item":
        gen_kwargs["seed_scope"] = self.seed_scope
    if self.stop_strings:
        gen_kwargs["stop_strings"] = self.stop_strings
    if self.stop_token_ids:
        gen_kwargs["stop_token_ids"] = self.stop_token_ids
    return gen_kwargs

HookEntry dataclass

One state control's torch-hook contribution, consumed by in-process sessions.

Attributes:

Name Type Description
hooks Mapping[str, list]

Hook specifications keyed by phase ("pre", "forward", "backward"), as returned by StateControl.get_hooks.

Source code in steerability/algorithms/core/execution/payloads.py
467
468
469
470
471
472
473
474
475
476
@dataclass(frozen=True, slots=True, eq=False)
class HookEntry:
    """One state control's torch-hook contribution, consumed by in-process sessions.

    Attributes:
        hooks: Hook specifications keyed by phase (`"pre"`, `"forward"`, `"backward"`), as
            returned by `StateControl.get_hooks`.
    """

    hooks: Mapping[str, list]
hooks instance-attribute

InterventionEntry dataclass

One state control's intervention-spec contribution, consumed by intervention-capable backends.

Attributes:

Name Type Description
spec InterventionSpec

The serialized intervention.

Source code in steerability/algorithms/core/execution/payloads.py
479
480
481
482
483
484
485
486
487
488
@dataclass(frozen=True, slots=True)
class InterventionEntry:
    """One state control's intervention-spec contribution, consumed by intervention-capable
    backends.

    Attributes:
        spec: The serialized intervention.
    """

    spec: InterventionSpec
spec instance-attribute

InterventionKinds dataclass

Activation-intervention kinds a backend executes, by permanent wire name.

Wire names mirror toolkit class names (AdditiveTransform serializes as "additive", SumThreshold as "sum_threshold"), so the mapping is definitional rather than maintained. Kind names are permanent and their meanings never change; new behavior is a new kind. Compatibility is set containment on kind names.

Attributes:

Name Type Description
transforms frozenset[str]

Transform kinds, e.g. {"additive", "projection", "rotation", "head_additive"}.

modifiers frozenset[str]

Wrapper-transform kinds, e.g. {"norm_preserving", "alignment_adaptive"}.

scopes frozenset[str]

Token-scope kinds, e.g. {"all", "after_prompt", "last_k", "from_position"}.

readouts frozenset[str]

Gate readout kinds, e.g. {"affine", "cosine", "projected_cosine"}; an ungated op needs none.

rules frozenset[str]

Gate rule kinds, e.g. {"sum_threshold", "per_key_threshold"}.

constraints Mapping[str, str]

Per-kind execution constraints, e.g. {"head_additive": "tensor_parallel_size==1"}. Informational; containment checks ignore this field.

Source code in steerability/algorithms/core/execution/contracts.py
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
@dataclass(frozen=True, slots=True)
class InterventionKinds:
    """Activation-intervention kinds a backend executes, by permanent wire name.

    Wire names mirror toolkit class names (`AdditiveTransform` serializes as `"additive"`,
    `SumThreshold` as `"sum_threshold"`), so the mapping is definitional rather than
    maintained. Kind names are permanent and their meanings never change; new behavior is a
    new kind. Compatibility is set containment on kind names.

    Attributes:
        transforms: Transform kinds, e.g. `{"additive", "projection", "rotation",
            "head_additive"}`.
        modifiers: Wrapper-transform kinds, e.g. `{"norm_preserving", "alignment_adaptive"}`.
        scopes: Token-scope kinds, e.g. `{"all", "after_prompt", "last_k", "from_position"}`.
        readouts: Gate readout kinds, e.g. `{"affine", "cosine", "projected_cosine"}`; an
            ungated op needs none.
        rules: Gate rule kinds, e.g. `{"sum_threshold", "per_key_threshold"}`.
        constraints: Per-kind execution constraints, e.g.
            `{"head_additive": "tensor_parallel_size==1"}`. Informational; containment checks
            ignore this field.
    """

    transforms: frozenset[str] = frozenset()
    modifiers: frozenset[str] = frozenset()
    scopes: frozenset[str] = frozenset()
    readouts: frozenset[str] = frozenset()
    rules: frozenset[str] = frozenset()
    constraints: Mapping[str, str] = field(default_factory=dict)

    def contains(self, required: "InterventionKinds") -> bool:
        """Return True when every required kind name is advertised."""
        return (
            required.transforms <= self.transforms
            and required.modifiers <= self.modifiers
            and required.scopes <= self.scopes
            and required.readouts <= self.readouts
            and required.rules <= self.rules
        )
constraints = field(default_factory=dict) class-attribute instance-attribute
modifiers = frozenset() class-attribute instance-attribute
readouts = frozenset() class-attribute instance-attribute
rules = frozenset() class-attribute instance-attribute
scopes = frozenset() class-attribute instance-attribute
transforms = frozenset() class-attribute instance-attribute
contains(required)

Return True when every required kind name is advertised.

Source code in steerability/algorithms/core/execution/contracts.py
84
85
86
87
88
89
90
91
92
def contains(self, required: "InterventionKinds") -> bool:
    """Return True when every required kind name is advertised."""
    return (
        required.transforms <= self.transforms
        and required.modifiers <= self.modifiers
        and required.scopes <= self.scopes
        and required.readouts <= self.readouts
        and required.rules <= self.rules
    )

InterventionSpec dataclass

A serialized activation intervention for intervention-capable backends.

Each op names its target layers, a transform (kind, scalar parameters, tensor payloads by artifact reference, and an ordered modifier list), a token scope, and an optional gate. Kind names are the advertised wire names; a worker rejects a spec containing a kind or field it does not list.

Attributes:

Name Type Description
ops tuple[Mapping[str, Any], ...]

The intervention ops, each a mapping with keys "layers", "transform", "scope", and "gate".

artifacts Mapping[str, Mapping[str, Any]]

Tensor payloads keyed by the content-addressed artifact ids the ops reference, each a mapping from tensor name to a float32 contiguous CPU tensor. Sessions materialize these into the registry the serving engine reads before submission. Excluded from equality, the wire form, and the canonical form.

Source code in steerability/algorithms/core/execution/payloads.py
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
@dataclass(frozen=True, slots=True)
class InterventionSpec:
    """A serialized activation intervention for intervention-capable backends.

    Each op names its target layers, a transform (kind, scalar parameters, tensor payloads by
    artifact reference, and an ordered modifier list), a token scope, and an optional gate. Kind
    names are the advertised wire names; a worker rejects a spec containing a kind or field it
    does not list.

    Attributes:
        ops: The intervention ops, each a mapping with keys `"layers"`, `"transform"`,
            `"scope"`, and `"gate"`.
        artifacts: Tensor payloads keyed by the content-addressed artifact ids the ops
            reference, each a mapping from tensor name to a float32 contiguous CPU tensor.
            Sessions materialize these into the registry the serving engine reads before
            submission. Excluded from equality, the wire form, and the canonical form.
    """

    ops: tuple[Mapping[str, Any], ...] = ()
    artifacts: Mapping[str, Mapping[str, Any]] = field(default_factory=dict, compare=False)

    def to_wire(self) -> dict[str, Any]:
        """The plain-data wire form, `{"ops": [...]}`, with nested mappings and sequences
        converted to dicts and lists."""
        return _plain({"ops": list(self.ops)})

    def artifact_ids(self) -> tuple[str, ...]:
        """Sorted unique artifact ids referenced anywhere in the ops (transform payloads,
        modifiers, and gate readouts)."""
        found: set[str] = set()
        _collect_artifact_ids(self.to_wire(), found)
        return tuple(sorted(found))

    def required_kinds(self) -> InterventionKinds:
        """The kind names this spec requires a backend to serve, as an `InterventionKinds`.

        Collects transform, modifier, scope, and gate readout/rule kind names from the ops; a
        backend whose negotiated kinds contain them can execute the spec.
        """
        transforms: set[str] = set()
        modifiers: set[str] = set()
        scopes: set[str] = set()
        readouts: set[str] = set()
        rules: set[str] = set()
        for op in self.to_wire()["ops"]:
            transform = op.get("transform", {})
            if "kind" in transform:
                transforms.add(transform["kind"])
            for modifier in transform.get("modifiers", []):
                if "kind" in modifier:
                    modifiers.add(modifier["kind"])
            scope = op.get("scope", {})
            if "kind" in scope:
                scopes.add(scope["kind"])
            gate = op.get("gate")
            if gate is not None:
                readout = gate.get("readout", {})
                if "kind" in readout:
                    readouts.add(readout["kind"])
                rule = gate.get("rule", {})
                if "kind" in rule:
                    rules.add(rule["kind"])
        return InterventionKinds(
            transforms=frozenset(transforms),
            modifiers=frozenset(modifiers),
            scopes=frozenset(scopes),
            readouts=frozenset(readouts),
            rules=frozenset(rules),
        )

    def canonical(self) -> str:
        """The canonical serialization, the form hashed for cache salting and provenance.

        Delegates to `vllm_hook_plugins.core.canonical.canonical_bytes` (sorted keys, compact
        separators, UTF-8), so the toolkit and the plugin agree byte-for-byte on the canonical
        form of a spec.

        Raises:
            ModuleNotFoundError: If `vllm_hook_plugins` is not installed. The message names
                the `steerability[vllm]` extra.
            TypeError: If an op contains a value with no JSON form. Tensors belong in
                artifacts, never inline.
        """
        canonical = require("vllm_hook_plugins.core.canonical")
        return canonical.canonical_bytes(self.to_wire()).decode("utf-8")

    def salt(self) -> str:
        """The reference cache salt for requests carrying this spec.

        Delegates to `vllm_hook_plugins.core.canonical.request_salt` over the wire form and
        the referenced artifact ids. Returns the 64-char lowercase-hex digest.

        Raises:
            ModuleNotFoundError: If `vllm_hook_plugins` is not installed. The message names
                the `steerability[vllm]` extra.
        """
        canonical = require("vllm_hook_plugins.core.canonical")
        return canonical.request_salt(self.to_wire(), list(self.artifact_ids()))
artifacts = field(default_factory=dict, compare=False) class-attribute instance-attribute
ops = () class-attribute instance-attribute
artifact_ids()

Sorted unique artifact ids referenced anywhere in the ops (transform payloads, modifiers, and gate readouts).

Source code in steerability/algorithms/core/execution/payloads.py
337
338
339
340
341
342
def artifact_ids(self) -> tuple[str, ...]:
    """Sorted unique artifact ids referenced anywhere in the ops (transform payloads,
    modifiers, and gate readouts)."""
    found: set[str] = set()
    _collect_artifact_ids(self.to_wire(), found)
    return tuple(sorted(found))
canonical()

The canonical serialization, the form hashed for cache salting and provenance.

Delegates to vllm_hook_plugins.core.canonical.canonical_bytes (sorted keys, compact separators, UTF-8), so the toolkit and the plugin agree byte-for-byte on the canonical form of a spec.

Raises:

Type Description
ModuleNotFoundError

If vllm_hook_plugins is not installed. The message names the steerability[vllm] extra.

TypeError

If an op contains a value with no JSON form. Tensors belong in artifacts, never inline.

Source code in steerability/algorithms/core/execution/payloads.py
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
def canonical(self) -> str:
    """The canonical serialization, the form hashed for cache salting and provenance.

    Delegates to `vllm_hook_plugins.core.canonical.canonical_bytes` (sorted keys, compact
    separators, UTF-8), so the toolkit and the plugin agree byte-for-byte on the canonical
    form of a spec.

    Raises:
        ModuleNotFoundError: If `vllm_hook_plugins` is not installed. The message names
            the `steerability[vllm]` extra.
        TypeError: If an op contains a value with no JSON form. Tensors belong in
            artifacts, never inline.
    """
    canonical = require("vllm_hook_plugins.core.canonical")
    return canonical.canonical_bytes(self.to_wire()).decode("utf-8")
required_kinds()

The kind names this spec requires a backend to serve, as an InterventionKinds.

Collects transform, modifier, scope, and gate readout/rule kind names from the ops; a backend whose negotiated kinds contain them can execute the spec.

Source code in steerability/algorithms/core/execution/payloads.py
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
def required_kinds(self) -> InterventionKinds:
    """The kind names this spec requires a backend to serve, as an `InterventionKinds`.

    Collects transform, modifier, scope, and gate readout/rule kind names from the ops; a
    backend whose negotiated kinds contain them can execute the spec.
    """
    transforms: set[str] = set()
    modifiers: set[str] = set()
    scopes: set[str] = set()
    readouts: set[str] = set()
    rules: set[str] = set()
    for op in self.to_wire()["ops"]:
        transform = op.get("transform", {})
        if "kind" in transform:
            transforms.add(transform["kind"])
        for modifier in transform.get("modifiers", []):
            if "kind" in modifier:
                modifiers.add(modifier["kind"])
        scope = op.get("scope", {})
        if "kind" in scope:
            scopes.add(scope["kind"])
        gate = op.get("gate")
        if gate is not None:
            readout = gate.get("readout", {})
            if "kind" in readout:
                readouts.add(readout["kind"])
            rule = gate.get("rule", {})
            if "kind" in rule:
                rules.add(rule["kind"])
    return InterventionKinds(
        transforms=frozenset(transforms),
        modifiers=frozenset(modifiers),
        scopes=frozenset(scopes),
        readouts=frozenset(readouts),
        rules=frozenset(rules),
    )
salt()

The reference cache salt for requests carrying this spec.

Delegates to vllm_hook_plugins.core.canonical.request_salt over the wire form and the referenced artifact ids. Returns the 64-char lowercase-hex digest.

Raises:

Type Description
ModuleNotFoundError

If vllm_hook_plugins is not installed. The message names the steerability[vllm] extra.

Source code in steerability/algorithms/core/execution/payloads.py
397
398
399
400
401
402
403
404
405
406
407
408
def salt(self) -> str:
    """The reference cache salt for requests carrying this spec.

    Delegates to `vllm_hook_plugins.core.canonical.request_salt` over the wire form and
    the referenced artifact ids. Returns the 64-char lowercase-hex digest.

    Raises:
        ModuleNotFoundError: If `vllm_hook_plugins` is not installed. The message names
            the `steerability[vllm]` extra.
    """
    canonical = require("vllm_hook_plugins.core.canonical")
    return canonical.request_salt(self.to_wire(), list(self.artifact_ids()))
to_wire()

The plain-data wire form, {"ops": [...]}, with nested mappings and sequences converted to dicts and lists.

Source code in steerability/algorithms/core/execution/payloads.py
332
333
334
335
def to_wire(self) -> dict[str, Any]:
    """The plain-data wire form, `{"ops": [...]}`, with nested mappings and sequences
    converted to dicts and lists."""
    return _plain({"ops": list(self.ops)})

ItemResult dataclass

The result of one generation item.

Attributes:

Name Type Description
index int

Position of the item in the submitted sequence.

output Output

The generation record. For n > 1 the record's batch dimension holds the candidates in request order and finish_reason reflects the first candidate.

Source code in steerability/algorithms/core/execution/payloads.py
577
578
579
580
581
582
583
584
585
586
587
588
@dataclass(frozen=True, slots=True, eq=False)
class ItemResult:
    """The result of one generation item.

    Attributes:
        index: Position of the item in the submitted sequence.
        output: The generation record. For `n > 1` the record's batch dimension holds the
            candidates in request order and `finish_reason` reflects the first candidate.
    """

    index: int
    output: Output
index instance-attribute
output instance-attribute

LoRAArtifact dataclass

A LoRA adapter handed across the role boundary; consuming it requires Capability.SERVE_LORA.

Attributes:

Name Type Description
path str

Adapter directory path.

base_model str

Model reference the adapter applies to.

provenance ArtifactProvenance

Identity of the producing side.

Source code in steerability/algorithms/core/execution/payloads.py
155
156
157
158
159
160
161
162
163
164
165
166
167
168
@dataclass(frozen=True, slots=True)
class LoRAArtifact:
    """A LoRA adapter handed across the role boundary; consuming it requires
    `Capability.SERVE_LORA`.

    Attributes:
        path: Adapter directory path.
        base_model: Model reference the adapter applies to.
        provenance: Identity of the producing side.
    """

    path: str
    base_model: str
    provenance: ArtifactProvenance = field(default_factory=ArtifactProvenance)
base_model instance-attribute
path instance-attribute
provenance = field(default_factory=ArtifactProvenance) class-attribute instance-attribute

ModelAccess

Bases: IntEnum

What a control's steer step requires of the pipeline model, as a cumulative ladder.

Attributes:

Name Type Description
FACTS

Structural facts (session.layout) and a tokenizer.

ROLLOUTS

FACTS plus generation and scoring through the session.

CAPTURE

ROLLOUTS plus hidden-state capture through the session.

MODULE

The model as a live torch.nn.Module in the client process.

Source code in steerability/algorithms/core/execution/access.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class ModelAccess(enum.IntEnum):
    """What a control's steer step requires of the pipeline model, as a cumulative ladder.

    Attributes:
        FACTS: Structural facts (`session.layout`) and a tokenizer.
        ROLLOUTS: FACTS plus generation and scoring through the session.
        CAPTURE: ROLLOUTS plus hidden-state capture through the session.
        MODULE: The model as a live `torch.nn.Module` in the client process.
    """

    FACTS = 0
    ROLLOUTS = 1
    CAPTURE = 2
    MODULE = 3
CAPTURE = 2 class-attribute instance-attribute
FACTS = 0 class-attribute instance-attribute
MODULE = 3 class-attribute instance-attribute
ROLLOUTS = 1 class-attribute instance-attribute

ModelArtifact dataclass

An in-memory model handed across the role boundary; only the in-process backend can consume it.

Attributes:

Name Type Description
model Any

The loaded model.

provenance ArtifactProvenance

Identity of the producing side.

Source code in steerability/algorithms/core/execution/payloads.py
127
128
129
130
131
132
133
134
135
136
137
138
@dataclass(frozen=True, slots=True, eq=False)
class ModelArtifact:
    """An in-memory model handed across the role boundary; only the in-process backend can
    consume it.

    Attributes:
        model: The loaded model.
        provenance: Identity of the producing side.
    """

    model: Any
    provenance: ArtifactProvenance = field(default_factory=ArtifactProvenance)
model instance-attribute
provenance = field(default_factory=ArtifactProvenance) class-attribute instance-attribute

ModelFacts dataclass

Structural facts about the pipeline model, available without a live module tree.

Layer indices are the canonical coordinates for steer-phase layer selection; module names are an in-process serialization detail resolved only at hook construction time. Client-side tensor preparation uses the layout's dtype, and device placement is handled in process or by the worker rather than at steer time.

Attributes:

Name Type Description
num_layers int

Number of decoder layers.

hidden_size int

Residual-stream width.

num_attention_heads int | None

Number of attention heads, or None when the model config does not state one.

head_dim int | None

Per-head dimension, the config's nominal value (else hidden_size divided by num_attention_heads), or None when neither is derivable. Per-layer geometry can differ from this nominal value (some models alternate head dimensions across layers); consumers needing the actual per-layer geometry read head_geometry.

dtype str

Canonical dtype string, e.g. "bfloat16".

model_fingerprint str

A 16-character hex digest identifying the model weights and config.

model_type str | None

The config's model_type, or None when unknown.

model_ref str | None

The served model reference on engine backends, the loaded model's name_or_path in process, or None when unknown.

Source code in steerability/algorithms/core/execution/payloads.py
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
@dataclass(frozen=True, slots=True)
class ModelFacts:
    """Structural facts about the pipeline model, available without a live module tree.

    Layer indices are the canonical coordinates for steer-phase layer selection; module names
    are an in-process serialization detail resolved only at hook construction time. Client-side
    tensor preparation uses the layout's dtype, and device placement is handled in process or by
    the worker rather than at steer time.


    Attributes:
        num_layers: Number of decoder layers.
        hidden_size: Residual-stream width.
        num_attention_heads: Number of attention heads, or None when the model config does not
            state one.
        head_dim: Per-head dimension, the config's nominal value (else `hidden_size` divided by
            `num_attention_heads`), or None when neither is derivable. Per-layer geometry can
            differ from this nominal value (some models alternate head dimensions across layers);
            consumers needing the actual per-layer geometry read `head_geometry`.
        dtype: Canonical dtype string, e.g. `"bfloat16"`.
        model_fingerprint: A 16-character hex digest identifying the model weights and config.
        model_type: The config's `model_type`, or None when unknown.
        model_ref: The served model reference on engine backends, the loaded model's
            `name_or_path` in process, or None when unknown.
    """

    num_layers: int
    hidden_size: int
    num_attention_heads: int | None
    head_dim: int | None
    dtype: str
    model_fingerprint: str
    model_type: str | None = None
    model_ref: str | None = None
dtype instance-attribute
head_dim instance-attribute
hidden_size instance-attribute
model_fingerprint instance-attribute
model_ref = None class-attribute instance-attribute
model_type = None class-attribute instance-attribute
num_attention_heads instance-attribute
num_layers instance-attribute

PartialBatchError

Bases: RuntimeError

Raised when some items of a fan-out failed after retries while others succeeded.

Attributes:

Name Type Description
results

The successful per-item results, in item order (ItemResults for generation, per-item score rows for scoring).

failures

(item_index, exception) pairs for the failed items, in item order.

Source code in steerability/algorithms/core/execution/fanout.py
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
class PartialBatchError(RuntimeError):
    """Raised when some items of a fan-out failed after retries while others succeeded.

    Attributes:
        results: The successful per-item results, in item order (`ItemResult`s for generation,
            per-item score rows for scoring).
        failures: `(item_index, exception)` pairs for the failed items, in item order.
    """

    def __init__(
        self,
        results: Sequence[ItemResult] | Sequence[Any],
        failures: Sequence[tuple[int, Exception]],
    ) -> None:
        self.results = tuple(results)
        self.failures = tuple(failures)
        summary = "; ".join(
            f"item {index}: {type(error).__name__}: {error}" for index, error in self.failures
        )
        super().__init__(
            f"{len(self.failures)} of {len(self.results) + len(self.failures)} items failed "
            f"after retries ({summary}). Successful results are on `results`; re-issue the "
            "indices on `failed_indices`."
        )

    @property
    def failed_indices(self) -> tuple[int, ...]:
        """Indices of the failed items, re-issuable as a remainder batch."""
        return tuple(index for index, _ in self.failures)
failed_indices property

Indices of the failed items, re-issuable as a remainder batch.

failures = tuple(failures) instance-attribute
results = tuple(results) instance-attribute

PlannedFit dataclass

One fit artifact's venue in the plan.

Fits execute inside their owning control's steer step, so a fit's venue is the step's.

Attributes:

Name Type Description
control str

Class name of the control whose steer runs the fit.

artifact str

Class name of the fit source or recipe, e.g. "ContrastiveFit".

artifact_class ArtifactClass

"direction" for translation-robust fits (mean-difference or PCA directions) or "calibrated" for artifacts compared against absolute activation statistics (probe biases, gate thresholds).

venue Venue

Where the fit runs.

Source code in steerability/algorithms/core/execution/access.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
@dataclass(frozen=True, slots=True)
class PlannedFit:
    """One fit artifact's venue in the plan.

    Fits execute inside their owning control's steer step, so a fit's venue is the step's.

    Attributes:
        control: Class name of the control whose steer runs the fit.
        artifact: Class name of the fit source or recipe, e.g. `"ContrastiveFit"`.
        artifact_class: `"direction"` for translation-robust fits (mean-difference or PCA
            directions) or `"calibrated"` for artifacts compared against absolute activation
            statistics (probe biases, gate thresholds).
        venue: Where the fit runs.
    """

    control: str
    artifact: str
    artifact_class: ArtifactClass
    venue: Venue
artifact instance-attribute
artifact_class instance-attribute
control instance-attribute
venue instance-attribute

PlannedStep dataclass

One enabled control's steer step in the plan.

Attributes:

Name Type Description
control str

Class name of the control.

access ModelAccess

The control's declared steer access.

venue Venue

Where the step runs. "live" is the persistent in-process model on the Hugging Face backend, "session" the engine session, and "stage" the temporary in-process model on engine backends.

Source code in steerability/algorithms/core/execution/access.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@dataclass(frozen=True, slots=True)
class PlannedStep:
    """One enabled control's steer step in the plan.

    Attributes:
        control: Class name of the control.
        access: The control's declared steer access.
        venue: Where the step runs. `"live"` is the persistent in-process model on the Hugging
            Face backend, `"session"` the engine session, and `"stage"` the temporary
            in-process model on engine backends.
    """

    control: str
    access: ModelAccess
    venue: Venue
access instance-attribute
control instance-attribute
venue instance-attribute

PreparedPrompt dataclass

A sum type over messages | text | token_ids for one prompt, plus metadata.

Exactly one of text, messages, or token_ids is set at construction. Tokenization is forced only when a consumer needs token ids (resolve_token_ids); the in-process resolution reproduces the pipeline's tokenization calls, so resolved ids match the early-tokenized path.

Attributes:

Name Type Description
text str | None

A plain-text prompt, or None.

messages tuple[Mapping, ...] | None

One conversation as a tuple of message mappings, or None.

token_ids Tensor | None

Token ids of shape [1, seq_len], or None until resolved.

attention_mask Tensor | None

Attention mask matching token_ids, or None.

is_single bool

Whether the originating call passed a single (non-batched) prompt.

message_handled frozenset[int]

id()s of input controls whose adapt_messages already performed the adaptation for this prompt.

Source code in steerability/algorithms/core/execution/payloads.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
@dataclass(frozen=True, slots=True, eq=False)
class PreparedPrompt:
    """A sum type over `messages | text | token_ids` for one prompt, plus metadata.

    Exactly one of `text`, `messages`, or `token_ids` is set at construction. Tokenization is
    forced only when a consumer needs token ids (`resolve_token_ids`); the in-process resolution
    reproduces the pipeline's tokenization calls, so resolved ids match the early-tokenized path.

    Attributes:
        text: A plain-text prompt, or None.
        messages: One conversation as a tuple of message mappings, or None.
        token_ids: Token ids of shape `[1, seq_len]`, or None until resolved.
        attention_mask: Attention mask matching `token_ids`, or None.
        is_single: Whether the originating call passed a single (non-batched) prompt.
        message_handled: `id()`s of input controls whose `adapt_messages` already performed the
            adaptation for this prompt.
    """

    text: str | None = None
    messages: tuple[Mapping, ...] | None = None
    token_ids: torch.Tensor | None = None
    attention_mask: torch.Tensor | None = None
    is_single: bool = True
    message_handled: frozenset[int] = frozenset()

    def __post_init__(self) -> None:
        sources = [
            name for name, value in (
                ("text", self.text), ("messages", self.messages), ("token_ids", self.token_ids),
            ) if value is not None
        ]
        if len(sources) != 1:
            raise ValueError(
                f"PreparedPrompt requires exactly one of text, messages, or token_ids; got "
                f"{', '.join(sources) or 'none'}."
            )

    @classmethod
    def from_text(cls, text: str) -> "PreparedPrompt":
        """Build a text-form prompt."""
        return cls(text=text)

    @classmethod
    def from_messages(cls, messages: list[Mapping] | tuple[Mapping, ...]) -> "PreparedPrompt":
        """Build a message-form prompt from one conversation."""
        return cls(messages=tuple(messages))

    @classmethod
    def from_token_ids(
        cls,
        token_ids: torch.Tensor | list[int],
        attention_mask: torch.Tensor | None = None,
    ) -> "PreparedPrompt":
        """Build a token-form prompt from a 1-D or `[1, seq_len]` tensor or a `list[int]`.

        Raises:
            ValueError: If `token_ids` carries more than one row; a prompt is one row.
        """
        if isinstance(token_ids, list):
            token_ids = torch.tensor(token_ids, dtype=torch.long)
        if token_ids.ndim == 1:
            token_ids = token_ids.unsqueeze(0)
        if token_ids.ndim != 2 or token_ids.size(0) != 1:
            raise ValueError(
                f"A PreparedPrompt holds one prompt row; got shape {tuple(token_ids.shape)}."
            )
        if attention_mask is not None and attention_mask.ndim == 1:
            attention_mask = attention_mask.unsqueeze(0)
        return cls(token_ids=token_ids, attention_mask=attention_mask)

    def resolve_token_ids(self, tokenizer: "PreTrainedTokenizerBase | None") -> "PreparedPrompt":
        """Return a token-form copy of this prompt, tokenizing text or messages when needed.

        Text prompts tokenize via `tokenizer(...)`; message prompts via
        `tokenizer.apply_chat_template(..., add_generation_prompt=True)`. Both match the
        pipeline's own tokenization calls. A prompt already in token form is returned unchanged.

        Args:
            tokenizer: The pipeline tokenizer.

        Returns:
            A `PreparedPrompt` with `token_ids` (and, when available, `attention_mask`) set.

        Raises:
            ValueError: If tokenization is required but `tokenizer` is None.
        """
        if self.token_ids is not None:
            return self
        if tokenizer is None:
            raise ValueError("A tokenizer is required to resolve this prompt to token ids.")

        if self.text is not None:
            encoded = tokenizer([self.text], return_tensors="pt", padding=True)
            return replace(
                self,
                text=None,
                token_ids=encoded["input_ids"],
                attention_mask=encoded.get("attention_mask"),
            )

        encoded = tokenizer.apply_chat_template(
            [list(self.messages)],
            return_tensors="pt",
            padding=True,
            add_generation_prompt=True,
            return_dict=True,
        )
        input_ids = encoded["input_ids"]
        attention_mask = encoded.get("attention_mask")
        if input_ids.ndim == 1:
            input_ids = input_ids.unsqueeze(0)
            if attention_mask is not None:
                attention_mask = attention_mask.unsqueeze(0)
        return replace(self, messages=None, token_ids=input_ids, attention_mask=attention_mask)
attention_mask = None class-attribute instance-attribute
is_single = True class-attribute instance-attribute
message_handled = frozenset() class-attribute instance-attribute
messages = None class-attribute instance-attribute
text = None class-attribute instance-attribute
token_ids = None class-attribute instance-attribute
from_messages(messages) classmethod

Build a message-form prompt from one conversation.

Source code in steerability/algorithms/core/execution/payloads.py
216
217
218
219
@classmethod
def from_messages(cls, messages: list[Mapping] | tuple[Mapping, ...]) -> "PreparedPrompt":
    """Build a message-form prompt from one conversation."""
    return cls(messages=tuple(messages))
from_text(text) classmethod

Build a text-form prompt.

Source code in steerability/algorithms/core/execution/payloads.py
211
212
213
214
@classmethod
def from_text(cls, text: str) -> "PreparedPrompt":
    """Build a text-form prompt."""
    return cls(text=text)
from_token_ids(token_ids, attention_mask=None) classmethod

Build a token-form prompt from a 1-D or [1, seq_len] tensor or a list[int].

Raises:

Type Description
ValueError

If token_ids carries more than one row; a prompt is one row.

Source code in steerability/algorithms/core/execution/payloads.py
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
@classmethod
def from_token_ids(
    cls,
    token_ids: torch.Tensor | list[int],
    attention_mask: torch.Tensor | None = None,
) -> "PreparedPrompt":
    """Build a token-form prompt from a 1-D or `[1, seq_len]` tensor or a `list[int]`.

    Raises:
        ValueError: If `token_ids` carries more than one row; a prompt is one row.
    """
    if isinstance(token_ids, list):
        token_ids = torch.tensor(token_ids, dtype=torch.long)
    if token_ids.ndim == 1:
        token_ids = token_ids.unsqueeze(0)
    if token_ids.ndim != 2 or token_ids.size(0) != 1:
        raise ValueError(
            f"A PreparedPrompt holds one prompt row; got shape {tuple(token_ids.shape)}."
        )
    if attention_mask is not None and attention_mask.ndim == 1:
        attention_mask = attention_mask.unsqueeze(0)
    return cls(token_ids=token_ids, attention_mask=attention_mask)
resolve_token_ids(tokenizer)

Return a token-form copy of this prompt, tokenizing text or messages when needed.

Text prompts tokenize via tokenizer(...); message prompts via tokenizer.apply_chat_template(..., add_generation_prompt=True). Both match the pipeline's own tokenization calls. A prompt already in token form is returned unchanged.

Parameters:

Name Type Description Default
tokenizer PreTrainedTokenizerBase | None

The pipeline tokenizer.

required

Returns:

Type Description
PreparedPrompt

A PreparedPrompt with token_ids (and, when available, attention_mask) set.

Raises:

Type Description
ValueError

If tokenization is required but tokenizer is None.

Source code in steerability/algorithms/core/execution/payloads.py
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
def resolve_token_ids(self, tokenizer: "PreTrainedTokenizerBase | None") -> "PreparedPrompt":
    """Return a token-form copy of this prompt, tokenizing text or messages when needed.

    Text prompts tokenize via `tokenizer(...)`; message prompts via
    `tokenizer.apply_chat_template(..., add_generation_prompt=True)`. Both match the
    pipeline's own tokenization calls. A prompt already in token form is returned unchanged.

    Args:
        tokenizer: The pipeline tokenizer.

    Returns:
        A `PreparedPrompt` with `token_ids` (and, when available, `attention_mask`) set.

    Raises:
        ValueError: If tokenization is required but `tokenizer` is None.
    """
    if self.token_ids is not None:
        return self
    if tokenizer is None:
        raise ValueError("A tokenizer is required to resolve this prompt to token ids.")

    if self.text is not None:
        encoded = tokenizer([self.text], return_tensors="pt", padding=True)
        return replace(
            self,
            text=None,
            token_ids=encoded["input_ids"],
            attention_mask=encoded.get("attention_mask"),
        )

    encoded = tokenizer.apply_chat_template(
        [list(self.messages)],
        return_tensors="pt",
        padding=True,
        add_generation_prompt=True,
        return_dict=True,
    )
    input_ids = encoded["input_ids"]
    attention_mask = encoded.get("attention_mask")
    if input_ids.ndim == 1:
        input_ids = input_ids.unsqueeze(0)
        if attention_mask is not None:
            attention_mask = attention_mask.unsqueeze(0)
    return replace(self, messages=None, token_ids=input_ids, attention_mask=attention_mask)

ProcessorKinds dataclass

Engine-hosted logit-processor kinds a backend executes, by permanent wire name.

Attributes:

Name Type Description
processors frozenset[str]

Processor kinds, e.g. {"constraint"}.

Source code in steerability/algorithms/core/execution/contracts.py
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
@dataclass(frozen=True, slots=True)
class ProcessorKinds:
    """Engine-hosted logit-processor kinds a backend executes, by permanent wire name.

    Attributes:
        processors: Processor kinds, e.g. `{"constraint"}`.
    """

    processors: frozenset[str] = frozenset()

    def contains(self, required: "ProcessorKinds") -> bool:
        """Return True when every required kind name is advertised."""
        return required.processors <= self.processors
processors = frozenset() class-attribute instance-attribute
contains(required)

Return True when every required kind name is advertised.

Source code in steerability/algorithms/core/execution/contracts.py
105
106
107
def contains(self, required: "ProcessorKinds") -> bool:
    """Return True when every required kind name is advertised."""
    return required.processors <= self.processors

ProcessorSpec dataclass

A serialized per-step logit processor for backends advertising engine-hosted logit math.

Attributes:

Name Type Description
kind str

The advertised processor kind name, e.g. "constraint".

params Mapping[str, Any]

Processor parameters.

Source code in steerability/algorithms/core/execution/payloads.py
411
412
413
414
415
416
417
418
419
420
421
@dataclass(frozen=True, slots=True)
class ProcessorSpec:
    """A serialized per-step logit processor for backends advertising engine-hosted logit math.

    Attributes:
        kind: The advertised processor kind name, e.g. `"constraint"`.
        params: Processor parameters.
    """

    kind: str
    params: Mapping[str, Any] = field(default_factory=dict)
kind instance-attribute
params = field(default_factory=dict) class-attribute instance-attribute

ProcessorSpecEntry dataclass

One output control's engine-hosted processor contribution.

Attributes:

Name Type Description
spec ProcessorSpec

The serialized processor.

Source code in steerability/algorithms/core/execution/payloads.py
522
523
524
525
526
527
528
529
530
@dataclass(frozen=True, slots=True)
class ProcessorSpecEntry:
    """One output control's engine-hosted processor contribution.

    Attributes:
        spec: The serialized processor.
    """

    spec: ProcessorSpec
spec instance-attribute

Requirements dataclass

Phase-keyed backend requirements computed by a control instance.

Each phase holds a tuple of Alternatives (a disjunction); an empty tuple requires nothing beyond the session contract, which includes the model layout. The steer phase carries no requirements; a control declares its steer-time model access through steer_access().

Attributes:

Name Type Description
generate tuple[Alternative, ...]

Alternatives for the generate phase.

score tuple[Alternative, ...]

Alternatives for the score phase.

spec_constraints tuple[SpecConstraint, ...]

Backend-configuration predicates, each evaluated against the spec of every phase it names.

Source code in steerability/algorithms/core/execution/contracts.py
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
@dataclass(frozen=True, slots=True)
class Requirements:
    """Phase-keyed backend requirements computed by a control instance.

    Each phase holds a tuple of `Alternative`s (a disjunction); an empty tuple requires nothing
    beyond the session contract, which includes the model layout. The steer phase carries no
    requirements; a control declares its steer-time model access through `steer_access()`.

    Attributes:
        generate: Alternatives for the generate phase.
        score: Alternatives for the score phase.
        spec_constraints: Backend-configuration predicates, each evaluated against the spec of
            every phase it names.
    """

    generate: tuple[Alternative, ...] = ()
    score: tuple[Alternative, ...] = ()
    spec_constraints: tuple[SpecConstraint, ...] = ()

    def for_phase(self, phase: str) -> tuple[Alternative, ...]:
        """The alternatives for `phase` (one of `"generate"`, `"score"`).

        Raises:
            ValueError: If `phase` is not a known phase name.
        """
        if phase not in PHASES:
            raise ValueError(f"Unknown phase {phase!r}; phases are {', '.join(PHASES)}.")
        return getattr(self, phase)
generate = () class-attribute instance-attribute
score = () class-attribute instance-attribute
spec_constraints = () class-attribute instance-attribute
for_phase(phase)

The alternatives for phase (one of "generate", "score").

Raises:

Type Description
ValueError

If phase is not a known phase name.

Source code in steerability/algorithms/core/execution/contracts.py
322
323
324
325
326
327
328
329
330
def for_phase(self, phase: str) -> tuple[Alternative, ...]:
    """The alternatives for `phase` (one of `"generate"`, `"score"`).

    Raises:
        ValueError: If `phase` is not a known phase name.
    """
    if phase not in PHASES:
        raise ValueError(f"Unknown phase {phase!r}; phases are {', '.join(PHASES)}.")
    return getattr(self, phase)

ScoringItem dataclass

One prompt's unit of scoring work (teacher-forced reference tokens).

Only controls participating in scoring contribute entries, and stopping criteria are never applied (there is no loop to stop).

Attributes:

Name Type Description
prompt PreparedPrompt

The prepared prompt.

ref_output_ids Tensor

Reference tokens to score, shape [ref_len] or [1, ref_len].

state_entries tuple[StateControlEntry, ...]

Enabled state controls' contributions, in controls-list order.

output_entries tuple[OutputControlEntry, ...]

Scoring-participant output controls' contributions, in controls-list order.

Source code in steerability/algorithms/core/execution/payloads.py
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
@dataclass(frozen=True, slots=True, eq=False)
class ScoringItem:
    """One prompt's unit of scoring work (teacher-forced reference tokens).

    Only controls participating in scoring contribute entries, and stopping criteria are never
    applied (there is no loop to stop).

    Attributes:
        prompt: The prepared prompt.
        ref_output_ids: Reference tokens to score, shape `[ref_len]` or `[1, ref_len]`.
        state_entries: Enabled state controls' contributions, in controls-list order.
        output_entries: Scoring-participant output controls' contributions, in controls-list
            order.
    """

    prompt: PreparedPrompt
    ref_output_ids: torch.Tensor
    state_entries: tuple[StateControlEntry, ...] = ()
    output_entries: tuple[OutputControlEntry, ...] = ()
output_entries = () class-attribute instance-attribute
prompt instance-attribute
ref_output_ids instance-attribute
state_entries = () class-attribute instance-attribute

SpecConstraint dataclass

A predicate over a resolved BackendSpec, for backend-configuration facts.

Attributes:

Name Type Description
description str

The unsupported-verdict message shown when the predicate fails. It should name the conflict and a fix.

predicate Callable[[BackendSpec], bool]

Callable evaluated against the phase's BackendSpec; True means satisfied.

phases tuple[str, ...]

Phases whose backend spec the predicate is evaluated against.

Source code in steerability/algorithms/core/execution/contracts.py
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
@dataclass(frozen=True, slots=True)
class SpecConstraint:
    """A predicate over a resolved `BackendSpec`, for backend-configuration facts.

    Attributes:
        description: The unsupported-verdict message shown when the predicate fails. It should
            name the conflict and a fix.
        predicate: Callable evaluated against the phase's `BackendSpec`; True means satisfied.
        phases: Phases whose backend spec the predicate is evaluated against.
    """

    description: str
    predicate: Callable[[BackendSpec], bool]
    phases: tuple[str, ...] = ("generate",)

    def __post_init__(self) -> None:
        unknown = [phase for phase in self.phases if phase not in PHASES]
        if unknown:
            raise ValueError(f"Unknown phases {unknown}; phases are {', '.join(PHASES)}.")
description instance-attribute
phases = ('generate',) class-attribute instance-attribute
predicate instance-attribute

StackEntry dataclass

One output control's live processor and criteria contribution, consumed by in-process sessions.

Attributes:

Name Type Description
logits_processors tuple

HF LogitsProcessor-style objects, in contribution order.

stopping_criteria tuple

HF StoppingCriteria-style objects, in contribution order.

Source code in steerability/algorithms/core/execution/payloads.py
494
495
496
497
498
499
500
501
502
503
504
505
@dataclass(frozen=True, slots=True, eq=False)
class StackEntry:
    """One output control's live processor and criteria contribution, consumed by in-process
    sessions.

    Attributes:
        logits_processors: HF `LogitsProcessor`-style objects, in contribution order.
        stopping_criteria: HF `StoppingCriteria`-style objects, in contribution order.
    """

    logits_processors: tuple = ()
    stopping_criteria: tuple = ()
logits_processors = () class-attribute instance-attribute
stopping_criteria = () class-attribute instance-attribute

SteerPlan dataclass

The deterministic steer plan for one backend configuration.

A pure function of the enabled controls' declarations and the backend spec, so the same configuration always yields the same plan.

Attributes:

Name Type Description
steps tuple[PlannedStep, ...]

Every enabled control, in pipeline order.

fits tuple[PlannedFit, ...]

Every fit artifact the steer phase will run, in pipeline order.

stages bool

True when a staged in-process model will be constructed.

notices tuple[str, ...]

Deterministic warnings the steer phase will emit (calibration crossings).

Source code in steerability/algorithms/core/execution/access.py
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
@dataclass(frozen=True, slots=True)
class SteerPlan:
    """The deterministic steer plan for one backend configuration.

    A pure function of the enabled controls' declarations and the backend spec, so the same
    configuration always yields the same plan.

    Attributes:
        steps: Every enabled control, in pipeline order.
        fits: Every fit artifact the steer phase will run, in pipeline order.
        stages: True when a staged in-process model will be constructed.
        notices: Deterministic warnings the steer phase will emit (calibration crossings).
    """

    steps: tuple[PlannedStep, ...] = ()
    fits: tuple[PlannedFit, ...] = ()
    stages: bool = False
    notices: tuple[str, ...] = ()
fits = () class-attribute instance-attribute
notices = () class-attribute instance-attribute
stages = False class-attribute instance-attribute
steps = () class-attribute instance-attribute

SteeringSession

Bases: Protocol

One logical operation's scope on a backend; the unit of concurrency.

A session is opened per logical operation (one generation fan-out, one scoring call, one steer-phase fit) on every backend. The Backend owns the loaded model or engine; a session holds only per-operation state. Session-contract facts, provided by every backend and therefore never capability atoms, include token-id prompts, stop rules, minimum tokens, multiple candidates, seeded sampling, prompt-logprob scoring, and the model layout.

Source code in steerability/algorithms/core/execution/backend.py
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
@runtime_checkable
class SteeringSession(Protocol):
    """One logical operation's scope on a backend; the unit of concurrency.

    A session is opened per logical operation (one generation fan-out, one scoring call, one
    steer-phase fit) on every backend. The `Backend` owns the loaded model or engine; a session
    holds only per-operation state. Session-contract facts, provided by every backend and
    therefore never capability atoms, include token-id prompts, stop rules, minimum tokens,
    multiple candidates, seeded sampling, prompt-logprob scoring, and the model layout.
    """

    @property
    def layout(self) -> ModelFacts:
        """Structural facts about the session's model."""
        ...

    def generate(
        self,
        items: Sequence[GenerationItem],
        params: GenerationParams,
    ) -> list[ItemResult]:
        """Generate one result per item, in item order."""
        ...

    def score(
        self,
        items: Sequence[ScoringItem],
        params: GenerationParams,
    ) -> torch.Tensor:
        """Teacher-forced log-probabilities of each item's reference tokens, shape
        `[num_items, ref_len]`."""
        ...

    def capture(
        self,
        prompts: list[PreparedPrompt],
        layers: list[int],
        mode: Literal["all_tokens", "last_token"],
        location: Literal["layer_output", "layer_input"] = "layer_output",
    ) -> CaptureResult:
        """Capture hidden states for `prompts` at `layers`; requires
        `Capability.HIDDEN_CAPTURE`."""
        ...
layout property

Structural facts about the session's model.

capture(prompts, layers, mode, location='layer_output')

Capture hidden states for prompts at layers; requires Capability.HIDDEN_CAPTURE.

Source code in steerability/algorithms/core/execution/backend.py
69
70
71
72
73
74
75
76
77
78
def capture(
    self,
    prompts: list[PreparedPrompt],
    layers: list[int],
    mode: Literal["all_tokens", "last_token"],
    location: Literal["layer_output", "layer_input"] = "layer_output",
) -> CaptureResult:
    """Capture hidden states for `prompts` at `layers`; requires
    `Capability.HIDDEN_CAPTURE`."""
    ...
generate(items, params)

Generate one result per item, in item order.

Source code in steerability/algorithms/core/execution/backend.py
52
53
54
55
56
57
58
def generate(
    self,
    items: Sequence[GenerationItem],
    params: GenerationParams,
) -> list[ItemResult]:
    """Generate one result per item, in item order."""
    ...
score(items, params)

Teacher-forced log-probabilities of each item's reference tokens, shape [num_items, ref_len].

Source code in steerability/algorithms/core/execution/backend.py
60
61
62
63
64
65
66
67
def score(
    self,
    items: Sequence[ScoringItem],
    params: GenerationParams,
) -> torch.Tensor:
    """Teacher-forced log-probabilities of each item's reference tokens, shape
    `[num_items, ref_len]`."""
    ...

SupportFailure dataclass

One unsupported verdict.

Attributes:

Name Type Description
control str

Class name of the failing control.

phase str

The phase the verdict applies to ("generate" or "score").

message str

Stable, tested message naming the gap and a fix.

Source code in steerability/algorithms/core/execution/contracts.py
357
358
359
360
361
362
363
364
365
366
367
368
369
@dataclass(frozen=True, slots=True)
class SupportFailure:
    """One unsupported verdict.

    Attributes:
        control: Class name of the failing control.
        phase: The phase the verdict applies to (`"generate"` or `"score"`).
        message: Stable, tested message naming the gap and a fix.
    """

    control: str
    phase: str
    message: str
control instance-attribute
message instance-attribute
phase instance-attribute

SupportReport dataclass

The result of evaluating every enabled control against a backend.

Attributes:

Name Type Description
spec BackendSpec

The backend spec the phases were evaluated against.

plan SteerPlan

The deterministic steer plan for this configuration.

failures tuple[SupportFailure, ...]

All unsupported verdicts, in controls-list order then phase order.

Source code in steerability/algorithms/core/execution/contracts.py
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
@dataclass(frozen=True, slots=True)
class SupportReport:
    """The result of evaluating every enabled control against a backend.

    Attributes:
        spec: The backend spec the phases were evaluated against.
        plan: The deterministic steer plan for this configuration.
        failures: All unsupported verdicts, in controls-list order then phase order.
    """

    spec: BackendSpec
    plan: SteerPlan = field(default_factory=SteerPlan)
    failures: tuple[SupportFailure, ...] = ()

    @property
    def ok(self) -> bool:
        """True when no phase of any enabled control is unsupported."""
        return not self.failures

    def failures_for(self, *phases: str) -> tuple[SupportFailure, ...]:
        """The failures whose phase is among `phases`."""
        return tuple(failure for failure in self.failures if failure.phase in phases)

    def supported(self, *phases: str) -> bool:
        """True when no failure falls in any of `phases`."""
        return not self.failures_for(*phases)

    def raise_for(self, *phases: str) -> None:
        """Raise `UnsupportedPipelineError` listing every failing control in `phases`, if any."""
        if not self.supported(*phases):
            raise UnsupportedPipelineError(self, phases)
failures = () class-attribute instance-attribute
ok property

True when no phase of any enabled control is unsupported.

plan = field(default_factory=SteerPlan) class-attribute instance-attribute
spec instance-attribute
failures_for(*phases)

The failures whose phase is among phases.

Source code in steerability/algorithms/core/execution/contracts.py
391
392
393
def failures_for(self, *phases: str) -> tuple[SupportFailure, ...]:
    """The failures whose phase is among `phases`."""
    return tuple(failure for failure in self.failures if failure.phase in phases)
raise_for(*phases)

Raise UnsupportedPipelineError listing every failing control in phases, if any.

Source code in steerability/algorithms/core/execution/contracts.py
399
400
401
402
def raise_for(self, *phases: str) -> None:
    """Raise `UnsupportedPipelineError` listing every failing control in `phases`, if any."""
    if not self.supported(*phases):
        raise UnsupportedPipelineError(self, phases)
supported(*phases)

True when no failure falls in any of phases.

Source code in steerability/algorithms/core/execution/contracts.py
395
396
397
def supported(self, *phases: str) -> bool:
    """True when no failure falls in any of `phases`."""
    return not self.failures_for(*phases)

TransportError

Bases: RuntimeError

A transport-level failure (connection, timeout, or server-side 5xx) that is safe to retry.

Application-level rejections (validation errors, unknown parameters) are not transport errors and must not be wrapped in this type.

Source code in steerability/algorithms/core/execution/fanout.py
40
41
42
43
44
45
class TransportError(RuntimeError):
    """A transport-level failure (connection, timeout, or server-side 5xx) that is safe to retry.

    Application-level rejections (validation errors, unknown parameters) are not transport
    errors and must not be wrapped in this type.
    """

UnsupportedOperationError

Bases: RuntimeError

Raised when a session receives work it cannot execute on its backend.

Source code in steerability/algorithms/core/execution/contracts.py
353
354
class UnsupportedOperationError(RuntimeError):
    """Raised when a session receives work it cannot execute on its backend."""

UnsupportedPipelineError

Bases: RuntimeError

Raised when an operation targets a backend that does not support the pipeline.

Attributes:

Name Type Description
report

The SupportReport whose failures triggered the error.

Source code in steerability/algorithms/core/execution/contracts.py
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
class UnsupportedPipelineError(RuntimeError):
    """Raised when an operation targets a backend that does not support the pipeline.

    Attributes:
        report: The `SupportReport` whose failures triggered the error.
    """

    def __init__(self, report: "SupportReport", phases: tuple[str, ...]) -> None:
        self.report = report
        failures = report.failures_for(*phases)
        lines = "\n".join(f"- {failure.message}" for failure in failures)
        super().__init__(
            f"Pipeline is unsupported on the configured backends ({len(failures)} unsupported "
            f"requirement(s)):\n{lines}"
        )
report = report instance-attribute

any_of(*alternatives)

Combine alternatives into a disjunction, satisfied by its first satisfied alternative.

Parameters:

Name Type Description Default
*alternatives tuple[Alternative, ...] | Alternative

Alternative instances or tuples of them (as returned by needs).

()

Returns:

Type Description
tuple[Alternative, ...]

The flattened tuple of alternatives.

Source code in steerability/algorithms/core/execution/contracts.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
def any_of(*alternatives: tuple[Alternative, ...] | Alternative) -> tuple[Alternative, ...]:
    """Combine alternatives into a disjunction, satisfied by its first satisfied alternative.

    Args:
        *alternatives: `Alternative` instances or tuples of them (as returned by `needs`).

    Returns:
        The flattened tuple of alternatives.
    """
    flattened: list[Alternative] = []
    for alternative in alternatives:
        if isinstance(alternative, Alternative):
            flattened.append(alternative)
        else:
            flattened.extend(alternative)
    return tuple(flattened)

as_constraint_source(value)

Coerce a mapping with kind and value keys into a ConstraintSource.

Source code in steerability/algorithms/core/execution/payloads.py
65
66
67
68
69
70
71
72
73
def as_constraint_source(value: "ConstraintSource | Mapping[str, Any]") -> ConstraintSource:
    """Coerce a mapping with `kind` and `value` keys into a `ConstraintSource`."""
    if isinstance(value, ConstraintSource):
        return value
    if isinstance(value, Mapping):
        return ConstraintSource(kind=value["kind"], value=value["value"])
    raise TypeError(
        f"Expected a ConstraintSource or a mapping with 'kind' and 'value'; got {type(value).__name__}."
    )

capabilities_for_spec(spec)

The capability advertisement implied by spec, without constructing a backend.

Source code in steerability/algorithms/core/execution/backend.py
243
244
245
def capabilities_for_spec(spec: BackendSpec) -> BackendCapabilities:
    """The capability advertisement implied by `spec`, without constructing a backend."""
    return resolve_backend_class(spec).capabilities_for_spec(spec)

derive_item_seed(base_seed, operation_id, item_index)

Derive one item's sampling seed from a base seed, an operation id, and the item index.

The derivation is SHA-256("{base_seed}:{operation_id}:{item_index}") truncated to the first eight bytes (big-endian) and masked to 63 bits, so the result is a stable non-negative integer accepted by every backend sampler. Distinct item indices under one operation yield distinct streams while the whole fan-out stays reproducible from base_seed.

Parameters:

Name Type Description Default
base_seed int

The caller-supplied seed.

required
operation_id str

Identifier of the logical operation (stable across reruns).

required
item_index int

Position of the item in the submitted sequence.

required

Returns:

Type Description
int

The derived seed in [0, 2**63).

Source code in steerability/algorithms/core/execution/fanout.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def derive_item_seed(base_seed: int, operation_id: str, item_index: int) -> int:
    """Derive one item's sampling seed from a base seed, an operation id, and the item index.

    The derivation is `SHA-256("{base_seed}:{operation_id}:{item_index}")` truncated to the
    first eight bytes (big-endian) and masked to 63 bits, so the result is a stable non-negative
    integer accepted by every backend sampler. Distinct item indices under one operation yield
    distinct streams while the whole fan-out stays reproducible from `base_seed`.

    Args:
        base_seed: The caller-supplied seed.
        operation_id: Identifier of the logical operation (stable across reruns).
        item_index: Position of the item in the submitted sequence.

    Returns:
        The derived seed in `[0, 2**63)`.
    """
    digest = hashlib.sha256(f"{base_seed}:{operation_id}:{item_index}".encode("utf-8")).digest()
    return int.from_bytes(digest[:8], "big") & _SEED_MASK

evaluate_support(controls, spec, capabilities)

Evaluate every enabled control's requirements against a backend.

For each enabled control, control.requirements() is read once and each declared phase is checked against the backend's capabilities. Spec constraints are checked for every phase they name. Controls whose enabled attribute is False are skipped.

Parameters:

Name Type Description Default
controls Iterable[Any]

Control instances, in pipeline order.

required
spec BackendSpec

The backend spec.

required
capabilities BackendCapabilities

Capability advertisement of the backend.

required

Returns:

Type Description
SupportReport

A SupportReport whose failures hold one entry per unsupported (control, phase) pair

SupportReport

and per violated spec constraint.

Source code in steerability/algorithms/core/execution/contracts.py
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
def evaluate_support(
    controls: Iterable[Any],
    spec: BackendSpec,
    capabilities: BackendCapabilities,
) -> SupportReport:
    """Evaluate every enabled control's requirements against a backend.

    For each enabled control, `control.requirements()` is read once and each declared phase is
    checked against the backend's capabilities. Spec constraints are checked for every phase
    they name. Controls whose `enabled` attribute is False are skipped.

    Args:
        controls: Control instances, in pipeline order.
        spec: The backend spec.
        capabilities: Capability advertisement of the backend.

    Returns:
        A `SupportReport` whose `failures` hold one entry per unsupported (control, phase) pair
        and per violated spec constraint.
    """
    failures: list[SupportFailure] = []
    for control in controls:
        if not getattr(control, "enabled", True):
            continue
        control_name = type(control).__name__
        requirements: Requirements = control.requirements()

        for phase in PHASES:
            alternatives = requirements.for_phase(phase)
            if not alternatives:
                continue
            if any(alternative.satisfied_by(capabilities) for alternative in alternatives):
                continue
            failures.append(SupportFailure(
                control=control_name,
                phase=phase,
                message=_phase_failure_message(control_name, phase, spec, requirements, capabilities),
            ))

        for constraint in requirements.spec_constraints:
            for phase in constraint.phases:
                if constraint.predicate(spec):
                    continue
                failures.append(SupportFailure(
                    control=control_name,
                    phase=phase,
                    message=(
                        f"{control_name} is unsupported at {phase} on backend kind "
                        f"'{spec.kind}': {constraint.description}"
                    ),
                ))

    return SupportReport(spec=spec, failures=tuple(failures))

merge_lowered_params(params, contribution)

Merge one control's sampling-expressible contribution into params.

Stop strings and stop token ids union with the caller's (caller entries first, duplicates dropped); max_new_tokens takes the minimum and min_new_tokens the maximum of the present values, so a control can only tighten the caller's bounds.

Parameters:

Name Type Description Default
params GenerationParams

The caller-derived parameters.

required
contribution Mapping[str, Any]

Mapping over a subset of stop_strings, stop_token_ids, max_new_tokens, and min_new_tokens.

required

Returns:

Type Description
GenerationParams

The merged GenerationParams.

Raises:

Type Description
ValueError

If contribution carries a key outside the lowerable set, or if the tightened bounds cross (min_new_tokens exceeds max_new_tokens), raised on construction of the merged instance.

Source code in steerability/algorithms/core/execution/params.py
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
def merge_lowered_params(params: GenerationParams, contribution: Mapping[str, Any]) -> GenerationParams:
    """Merge one control's sampling-expressible contribution into `params`.

    Stop strings and stop token ids union with the caller's (caller entries first, duplicates
    dropped); `max_new_tokens` takes the minimum and `min_new_tokens` the maximum of the present
    values, so a control can only tighten the caller's bounds.

    Args:
        params: The caller-derived parameters.
        contribution: Mapping over a subset of `stop_strings`, `stop_token_ids`,
            `max_new_tokens`, and `min_new_tokens`.

    Returns:
        The merged `GenerationParams`.

    Raises:
        ValueError: If `contribution` carries a key outside the lowerable set, or if the tightened
            bounds cross (`min_new_tokens` exceeds `max_new_tokens`), raised on construction of the
            merged instance.
    """
    unknown = [key for key in contribution if key not in LOWERABLE_PARAM_NAMES]
    if unknown:
        raise ValueError(
            f"Control contributed non-lowerable generation parameter(s) {sorted(unknown)}; "
            f"lowerable parameters are {', '.join(LOWERABLE_PARAM_NAMES)}."
        )

    updates: dict[str, Any] = {}
    stop_strings = contribution.get("stop_strings")
    if stop_strings:
        if isinstance(stop_strings, str):
            stop_strings = (stop_strings,)
        merged = list(params.stop_strings)
        merged.extend(text for text in stop_strings if text not in merged)
        updates["stop_strings"] = tuple(merged)
    stop_token_ids = contribution.get("stop_token_ids")
    if stop_token_ids:
        merged_ids = list(params.stop_token_ids)
        merged_ids.extend(int(i) for i in stop_token_ids if int(i) not in merged_ids)
        updates["stop_token_ids"] = tuple(merged_ids)
    max_new = contribution.get("max_new_tokens")
    if max_new is not None:
        updates["max_new_tokens"] = (
            max_new if params.max_new_tokens is None else min(params.max_new_tokens, max_new)
        )
    min_new = contribution.get("min_new_tokens")
    if min_new is not None:
        updates["min_new_tokens"] = (
            min_new if params.min_new_tokens is None else max(params.min_new_tokens, min_new)
        )
    if not updates:
        return params
    return replace(params, **updates)

needs(*atoms, kinds=None, hint=None)

Build a single-alternative phase requirement.

Parameters:

Name Type Description Default
*atoms Capability

Capability atoms that must all be advertised.

()
kinds KindSet | tuple[KindSet, ...] | None

One kind set, or a tuple of kind sets, whose names must be contained in the backend's advertisement.

None
hint str | None

Optional fix text for unsupported-verdict messages.

None

Returns:

Type Description
tuple[Alternative, ...]

A one-element tuple of Alternative, directly assignable to a Requirements phase.

Source code in steerability/algorithms/core/execution/contracts.py
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
def needs(
    *atoms: Capability,
    kinds: KindSet | tuple[KindSet, ...] | None = None,
    hint: str | None = None,
) -> tuple[Alternative, ...]:
    """Build a single-alternative phase requirement.

    Args:
        *atoms: Capability atoms that must all be advertised.
        kinds: One kind set, or a tuple of kind sets, whose names must be contained in the
            backend's advertisement.
        hint: Optional fix text for unsupported-verdict messages.

    Returns:
        A one-element tuple of `Alternative`, directly assignable to a `Requirements` phase.
    """
    if kinds is None:
        kind_sets: tuple[KindSet, ...] = ()
    elif isinstance(kinds, tuple):
        kind_sets = kinds
    else:
        kind_sets = (kinds,)
    return (Alternative(atoms=frozenset(atoms), kinds=kind_sets, hint=hint),)

resolve_backend_class(spec)

The backend class registered for spec.kind.

Parameters:

Name Type Description Default
spec BackendSpec

The backend spec to resolve.

required

Returns:

Type Description
type[Backend]

The backend class. Importing the class does not require the backend's optional

type[Backend]

dependencies; constructing an instance may.

Raises:

Type Description
ValueError

If no backend class is registered for the spec's kind.

Source code in steerability/algorithms/core/execution/backend.py
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
def resolve_backend_class(spec: BackendSpec) -> "type[Backend]":
    """The backend class registered for `spec.kind`.

    Args:
        spec: The backend spec to resolve.

    Returns:
        The backend class. Importing the class does not require the backend's optional
        dependencies; constructing an instance may.

    Raises:
        ValueError: If no backend class is registered for the spec's kind.
    """
    entry = _BACKEND_CLASSES.get(spec.kind)
    if entry is None:
        raise ValueError(f"No backend class is registered for kind {spec.kind!r}.")
    module_name, attribute = entry
    return getattr(import_module(module_name), attribute)

run_bounded(tasks, max_concurrency)

Run tasks concurrently with at most max_concurrency in flight.

Parameters:

Name Type Description Default
tasks Sequence[Callable[[], Any]]

Zero-argument callables, one per item.

required
max_concurrency int

Maximum number of concurrently running tasks (at least 1).

required

Returns:

Type Description
list[Any | Exception]

One entry per task in task order: the task's return value, or the exception it raised.

Source code in steerability/algorithms/core/execution/fanout.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
def run_bounded(
    tasks: Sequence[Callable[[], Any]],
    max_concurrency: int,
) -> list[Any | Exception]:
    """Run `tasks` concurrently with at most `max_concurrency` in flight.

    Args:
        tasks: Zero-argument callables, one per item.
        max_concurrency: Maximum number of concurrently running tasks (at least 1).

    Returns:
        One entry per task in task order: the task's return value, or the exception it raised.
    """
    if not tasks:
        return []
    max_workers = max(1, min(int(max_concurrency), len(tasks)))
    if max_workers == 1:
        results: list[Any | Exception] = []
        for task in tasks:
            try:
                results.append(task())
            except Exception as error:
                results.append(error)
        return results
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = [executor.submit(task) for task in tasks]
        gathered: list[Any | Exception] = []
        for future in futures:
            error = future.exception()
            gathered.append(future.result() if error is None else error)
        return gathered

with_transport_retries(fn, *, max_attempts=3, backoff_base=0.5, sleep=time.sleep)

Call fn, retrying TransportErrors with exponential backoff.

Only TransportError triggers a retry; every other exception propagates immediately, since an application-level rejection will not change on resubmission.

Parameters:

Name Type Description Default
fn Callable[[], Any]

Zero-argument callable issuing one request.

required
max_attempts int

Total attempts including the first.

3
backoff_base float

Sleep before attempt k (1-based retries) is backoff_base * 2**(k-1).

0.5
sleep Callable[[float], None]

Sleep function (injectable for tests).

sleep

Returns:

Type Description
Any

fn()'s return value.

Raises:

Type Description
TransportError

The last attempt's error when every attempt failed.

Source code in steerability/algorithms/core/execution/fanout.py
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
def with_transport_retries(
    fn: Callable[[], Any],
    *,
    max_attempts: int = 3,
    backoff_base: float = 0.5,
    sleep: Callable[[float], None] = time.sleep,
) -> Any:
    """Call `fn`, retrying `TransportError`s with exponential backoff.

    Only `TransportError` triggers a retry; every other exception propagates immediately, since
    an application-level rejection will not change on resubmission.

    Args:
        fn: Zero-argument callable issuing one request.
        max_attempts: Total attempts including the first.
        backoff_base: Sleep before attempt `k` (1-based retries) is `backoff_base * 2**(k-1)`.
        sleep: Sleep function (injectable for tests).

    Returns:
        `fn()`'s return value.

    Raises:
        TransportError: The last attempt's error when every attempt failed.
    """
    attempt = 0
    while True:
        try:
            return fn()
        except TransportError as error:
            attempt += 1
            if attempt >= max_attempts:
                raise
            delay = backoff_base * (2 ** (attempt - 1))
            logger.debug("Transport error (%s); retrying in %.2fs.", error, delay)
            sleep(delay)

access

Model access declarations and the steer plan.

ModelAccess names what a control's steer step requires of the pipeline model. The pipeline satisfies every declaration deterministically: the bottom two rungs through the backend's session, CAPTURE through session capture where advertised and a staged in-process model where not, and MODULE through a staged in-process model always. SteerPlan records, per enabled control and per fit artifact, where the pipeline will run each steer step for one backend configuration.

ArtifactClass = Literal['direction', 'calibrated'] module-attribute
Venue = Literal['live', 'session', 'stage'] module-attribute
ModelAccess

Bases: IntEnum

What a control's steer step requires of the pipeline model, as a cumulative ladder.

Attributes:

Name Type Description
FACTS

Structural facts (session.layout) and a tokenizer.

ROLLOUTS

FACTS plus generation and scoring through the session.

CAPTURE

ROLLOUTS plus hidden-state capture through the session.

MODULE

The model as a live torch.nn.Module in the client process.

Source code in steerability/algorithms/core/execution/access.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class ModelAccess(enum.IntEnum):
    """What a control's steer step requires of the pipeline model, as a cumulative ladder.

    Attributes:
        FACTS: Structural facts (`session.layout`) and a tokenizer.
        ROLLOUTS: FACTS plus generation and scoring through the session.
        CAPTURE: ROLLOUTS plus hidden-state capture through the session.
        MODULE: The model as a live `torch.nn.Module` in the client process.
    """

    FACTS = 0
    ROLLOUTS = 1
    CAPTURE = 2
    MODULE = 3
CAPTURE = 2 class-attribute instance-attribute
FACTS = 0 class-attribute instance-attribute
MODULE = 3 class-attribute instance-attribute
ROLLOUTS = 1 class-attribute instance-attribute
PlannedFit dataclass

One fit artifact's venue in the plan.

Fits execute inside their owning control's steer step, so a fit's venue is the step's.

Attributes:

Name Type Description
control str

Class name of the control whose steer runs the fit.

artifact str

Class name of the fit source or recipe, e.g. "ContrastiveFit".

artifact_class ArtifactClass

"direction" for translation-robust fits (mean-difference or PCA directions) or "calibrated" for artifacts compared against absolute activation statistics (probe biases, gate thresholds).

venue Venue

Where the fit runs.

Source code in steerability/algorithms/core/execution/access.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
@dataclass(frozen=True, slots=True)
class PlannedFit:
    """One fit artifact's venue in the plan.

    Fits execute inside their owning control's steer step, so a fit's venue is the step's.

    Attributes:
        control: Class name of the control whose steer runs the fit.
        artifact: Class name of the fit source or recipe, e.g. `"ContrastiveFit"`.
        artifact_class: `"direction"` for translation-robust fits (mean-difference or PCA
            directions) or `"calibrated"` for artifacts compared against absolute activation
            statistics (probe biases, gate thresholds).
        venue: Where the fit runs.
    """

    control: str
    artifact: str
    artifact_class: ArtifactClass
    venue: Venue
artifact instance-attribute
artifact_class instance-attribute
control instance-attribute
venue instance-attribute
PlannedStep dataclass

One enabled control's steer step in the plan.

Attributes:

Name Type Description
control str

Class name of the control.

access ModelAccess

The control's declared steer access.

venue Venue

Where the step runs. "live" is the persistent in-process model on the Hugging Face backend, "session" the engine session, and "stage" the temporary in-process model on engine backends.

Source code in steerability/algorithms/core/execution/access.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@dataclass(frozen=True, slots=True)
class PlannedStep:
    """One enabled control's steer step in the plan.

    Attributes:
        control: Class name of the control.
        access: The control's declared steer access.
        venue: Where the step runs. `"live"` is the persistent in-process model on the Hugging
            Face backend, `"session"` the engine session, and `"stage"` the temporary
            in-process model on engine backends.
    """

    control: str
    access: ModelAccess
    venue: Venue
access instance-attribute
control instance-attribute
venue instance-attribute
SteerPlan dataclass

The deterministic steer plan for one backend configuration.

A pure function of the enabled controls' declarations and the backend spec, so the same configuration always yields the same plan.

Attributes:

Name Type Description
steps tuple[PlannedStep, ...]

Every enabled control, in pipeline order.

fits tuple[PlannedFit, ...]

Every fit artifact the steer phase will run, in pipeline order.

stages bool

True when a staged in-process model will be constructed.

notices tuple[str, ...]

Deterministic warnings the steer phase will emit (calibration crossings).

Source code in steerability/algorithms/core/execution/access.py
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
@dataclass(frozen=True, slots=True)
class SteerPlan:
    """The deterministic steer plan for one backend configuration.

    A pure function of the enabled controls' declarations and the backend spec, so the same
    configuration always yields the same plan.

    Attributes:
        steps: Every enabled control, in pipeline order.
        fits: Every fit artifact the steer phase will run, in pipeline order.
        stages: True when a staged in-process model will be constructed.
        notices: Deterministic warnings the steer phase will emit (calibration crossings).
    """

    steps: tuple[PlannedStep, ...] = ()
    fits: tuple[PlannedFit, ...] = ()
    stages: bool = False
    notices: tuple[str, ...] = ()
fits = () class-attribute instance-attribute
notices = () class-attribute instance-attribute
stages = False class-attribute instance-attribute
steps = () class-attribute instance-attribute

backend

The backend seam: Backend, SteeringSession, the backend registry, and the session wrapper drivers roll out through.

A Backend owns a loaded model, engine, or connection pool and its lifecycle, advertises capabilities, and creates sessions. A SteeringSession is one logical operation's scope on a backend and the unit of concurrency; sessions register hooks, execute items, and serve capture. The registry is a fixed mapping over the core-owned backend kinds; backend modules are imported on first resolution, so core carries no module-level dependency on steerability.backends.

SteeredSession

A SteeringSession whose generate and score inject a generation's control entries into every item, so a driver's rollouts carry the pipeline's steering without the driver knowing entries exist.

The pipeline builds one wrapper per logical generation and hands it to the decoding driver. On an in-process backend the injected tuple is empty, since the session hosts the generation's hooks ambiently for the span of the driver's decode; on spec-consuming backends the injected entries are the generation's lowered interventions with prompt-relative scopes rewritten to absolute positions at the generation's original prompt boundary, so re-prefilled continuation tokens are steered at their original positions.

Attributes:

Name Type Description
inner

The wrapped backend session.

state_entries

Entries injected ahead of each item's own.

generated_tokens

Running non-pad token count over every ItemResult.output.output_ids this wrapper has returned from generate, across all of a driver's rollouts. The pad id is read from the wrapped session's tokenizer; numel() counts every position when there is none. The pipeline reads this total after the driver's decode returns.

Source code in steerability/algorithms/core/execution/backend.py
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
class SteeredSession:
    """A `SteeringSession` whose `generate` and `score` inject a generation's control entries
    into every item, so a driver's rollouts carry the pipeline's steering without the driver
    knowing entries exist.

    The pipeline builds one wrapper per logical generation and hands it to the decoding
    driver. On an in-process backend the injected tuple is empty, since the session hosts the
    generation's hooks ambiently for the span of the driver's decode; on spec-consuming
    backends the injected entries are the generation's lowered interventions with
    prompt-relative scopes rewritten to absolute positions at the generation's original prompt
    boundary, so re-prefilled continuation tokens are steered at their original positions.

    Attributes:
        inner: The wrapped backend session.
        state_entries: Entries injected ahead of each item's own.
        generated_tokens: Running non-pad token count over every `ItemResult.output.output_ids`
            this wrapper has returned from `generate`, across all of a driver's rollouts. The pad
            id is read from the wrapped session's tokenizer; `numel()` counts every position when
            there is none. The pipeline reads this total after the driver's `decode` returns.
    """

    def __init__(self, inner, state_entries: tuple = ()):
        self.inner = inner
        self.state_entries = tuple(state_entries)
        self.generated_tokens = 0

    @property
    def layout(self):
        return self.inner.layout

    @property
    def tokenizer(self):
        return getattr(self.inner, "tokenizer", None)

    def _inject(self, item):
        if not self.state_entries:
            return item
        import dataclasses

        return dataclasses.replace(
            item, state_entries=self.state_entries + tuple(item.state_entries)
        )

    def generate(self, items, params):
        """Generate with the wrapper's entries injected into every item, accumulating the non-pad
        token count of every returned output into `generated_tokens`."""
        results = self.inner.generate([self._inject(item) for item in items], params)
        pad_token_id = getattr(getattr(self.inner, "tokenizer", None), "pad_token_id", None)
        for result in results:
            output_ids = result.output.output_ids
            if pad_token_id is None:
                self.generated_tokens += int(output_ids.numel())
            else:
                self.generated_tokens += int((output_ids != pad_token_id).sum().item())
        return results

    def score(self, items, params):
        """Score with the wrapper's entries injected into every item."""
        return self.inner.score([self._inject(item) for item in items], params)

    def capture(self, prompts, layers, mode, location="layer_output"):
        """Capture through the wrapped session, unsteered."""
        return self.inner.capture(prompts, layers, mode, location=location)
generated_tokens = 0 instance-attribute
inner = inner instance-attribute
layout property
state_entries = tuple(state_entries) instance-attribute
tokenizer property
capture(prompts, layers, mode, location='layer_output')

Capture through the wrapped session, unsteered.

Source code in steerability/algorithms/core/execution/backend.py
141
142
143
def capture(self, prompts, layers, mode, location="layer_output"):
    """Capture through the wrapped session, unsteered."""
    return self.inner.capture(prompts, layers, mode, location=location)
generate(items, params)

Generate with the wrapper's entries injected into every item, accumulating the non-pad token count of every returned output into generated_tokens.

Source code in steerability/algorithms/core/execution/backend.py
124
125
126
127
128
129
130
131
132
133
134
135
def generate(self, items, params):
    """Generate with the wrapper's entries injected into every item, accumulating the non-pad
    token count of every returned output into `generated_tokens`."""
    results = self.inner.generate([self._inject(item) for item in items], params)
    pad_token_id = getattr(getattr(self.inner, "tokenizer", None), "pad_token_id", None)
    for result in results:
        output_ids = result.output.output_ids
        if pad_token_id is None:
            self.generated_tokens += int(output_ids.numel())
        else:
            self.generated_tokens += int((output_ids != pad_token_id).sum().item())
    return results
score(items, params)

Score with the wrapper's entries injected into every item.

Source code in steerability/algorithms/core/execution/backend.py
137
138
139
def score(self, items, params):
    """Score with the wrapper's entries injected into every item."""
    return self.inner.score([self._inject(item) for item in items], params)
SteeringSession

Bases: Protocol

One logical operation's scope on a backend; the unit of concurrency.

A session is opened per logical operation (one generation fan-out, one scoring call, one steer-phase fit) on every backend. The Backend owns the loaded model or engine; a session holds only per-operation state. Session-contract facts, provided by every backend and therefore never capability atoms, include token-id prompts, stop rules, minimum tokens, multiple candidates, seeded sampling, prompt-logprob scoring, and the model layout.

Source code in steerability/algorithms/core/execution/backend.py
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
@runtime_checkable
class SteeringSession(Protocol):
    """One logical operation's scope on a backend; the unit of concurrency.

    A session is opened per logical operation (one generation fan-out, one scoring call, one
    steer-phase fit) on every backend. The `Backend` owns the loaded model or engine; a session
    holds only per-operation state. Session-contract facts, provided by every backend and
    therefore never capability atoms, include token-id prompts, stop rules, minimum tokens,
    multiple candidates, seeded sampling, prompt-logprob scoring, and the model layout.
    """

    @property
    def layout(self) -> ModelFacts:
        """Structural facts about the session's model."""
        ...

    def generate(
        self,
        items: Sequence[GenerationItem],
        params: GenerationParams,
    ) -> list[ItemResult]:
        """Generate one result per item, in item order."""
        ...

    def score(
        self,
        items: Sequence[ScoringItem],
        params: GenerationParams,
    ) -> torch.Tensor:
        """Teacher-forced log-probabilities of each item's reference tokens, shape
        `[num_items, ref_len]`."""
        ...

    def capture(
        self,
        prompts: list[PreparedPrompt],
        layers: list[int],
        mode: Literal["all_tokens", "last_token"],
        location: Literal["layer_output", "layer_input"] = "layer_output",
    ) -> CaptureResult:
        """Capture hidden states for `prompts` at `layers`; requires
        `Capability.HIDDEN_CAPTURE`."""
        ...
layout property

Structural facts about the session's model.

capture(prompts, layers, mode, location='layer_output')

Capture hidden states for prompts at layers; requires Capability.HIDDEN_CAPTURE.

Source code in steerability/algorithms/core/execution/backend.py
69
70
71
72
73
74
75
76
77
78
def capture(
    self,
    prompts: list[PreparedPrompt],
    layers: list[int],
    mode: Literal["all_tokens", "last_token"],
    location: Literal["layer_output", "layer_input"] = "layer_output",
) -> CaptureResult:
    """Capture hidden states for `prompts` at `layers`; requires
    `Capability.HIDDEN_CAPTURE`."""
    ...
generate(items, params)

Generate one result per item, in item order.

Source code in steerability/algorithms/core/execution/backend.py
52
53
54
55
56
57
58
def generate(
    self,
    items: Sequence[GenerationItem],
    params: GenerationParams,
) -> list[ItemResult]:
    """Generate one result per item, in item order."""
    ...
score(items, params)

Teacher-forced log-probabilities of each item's reference tokens, shape [num_items, ref_len].

Source code in steerability/algorithms/core/execution/backend.py
60
61
62
63
64
65
66
67
def score(
    self,
    items: Sequence[ScoringItem],
    params: GenerationParams,
) -> torch.Tensor:
    """Teacher-forced log-probabilities of each item's reference tokens, shape
    `[num_items, ref_len]`."""
    ...
capabilities_for_spec(spec)

The capability advertisement implied by spec, without constructing a backend.

Source code in steerability/algorithms/core/execution/backend.py
243
244
245
def capabilities_for_spec(spec: BackendSpec) -> BackendCapabilities:
    """The capability advertisement implied by `spec`, without constructing a backend."""
    return resolve_backend_class(spec).capabilities_for_spec(spec)
resolve_backend_class(spec)

The backend class registered for spec.kind.

Parameters:

Name Type Description Default
spec BackendSpec

The backend spec to resolve.

required

Returns:

Type Description
type[Backend]

The backend class. Importing the class does not require the backend's optional

type[Backend]

dependencies; constructing an instance may.

Raises:

Type Description
ValueError

If no backend class is registered for the spec's kind.

Source code in steerability/algorithms/core/execution/backend.py
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
def resolve_backend_class(spec: BackendSpec) -> "type[Backend]":
    """The backend class registered for `spec.kind`.

    Args:
        spec: The backend spec to resolve.

    Returns:
        The backend class. Importing the class does not require the backend's optional
        dependencies; constructing an instance may.

    Raises:
        ValueError: If no backend class is registered for the spec's kind.
    """
    entry = _BACKEND_CLASSES.get(spec.kind)
    if entry is None:
        raise ValueError(f"No backend class is registered for kind {spec.kind!r}.")
    module_name, attribute = entry
    return getattr(import_module(module_name), attribute)

contracts

Backend contracts: capability advertisement, the requirement language, and support verdicts.

A capability atom marks a mechanism that some control requirement can fail on; facts true of every backend belong to the session protocol contract instead. Kind sets state which activation edits, per-step logit processors, capture forms, and native constraints a capable backend executes. Controls state what a backend must provide as phase-keyed Requirements, and evaluate_support renders binary per-control, per-phase verdicts against the pipeline's backend. The steer phase produces no verdicts; steer-time model access is declared through ModelAccess and satisfied by the pipeline's steer plan.

KindSet = InterventionKinds | ProcessorKinds | CaptureKinds | ConstraintKinds module-attribute
PHASES = ('generate', 'score') module-attribute
Alternative dataclass

One way to satisfy a phase requirement, i.e., a conjunction of capability atoms with optional kind predicates over the backend's advertised kind sets.

Attributes:

Name Type Description
atoms frozenset[Capability]

Capability atoms that must all be advertised.

kinds tuple[KindSet, ...]

Kind sets whose names must all be contained in the backend's advertisement of the corresponding kind-set type.

hint str | None

Optional fix text used in unsupported-verdict messages in place of the default.

Source code in steerability/algorithms/core/execution/contracts.py
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
@dataclass(frozen=True, slots=True)
class Alternative:
    """One way to satisfy a phase requirement, i.e., a conjunction of capability atoms with
    optional kind predicates over the backend's advertised kind sets.

    Attributes:
        atoms: Capability atoms that must all be advertised.
        kinds: Kind sets whose names must all be contained in the backend's advertisement of the
            corresponding kind-set type.
        hint: Optional fix text used in unsupported-verdict messages in place of the default.
    """

    atoms: frozenset[Capability] = frozenset()
    kinds: tuple[KindSet, ...] = ()
    hint: str | None = None

    def satisfied_by(self, capabilities: BackendCapabilities) -> bool:
        """Return True when every atom is advertised and every kind set is contained."""
        if not self.atoms <= capabilities.atoms:
            return False
        for kind_set in self.kinds:
            advertised = _advertised_for(kind_set, capabilities)
            if advertised is None or not advertised.contains(kind_set):
                return False
        return True

    def missing(self, capabilities: BackendCapabilities) -> list[str]:
        """Names of the atoms and kind sets this alternative needs but `capabilities` lacks."""
        gaps = [atom.name for atom in sorted(self.atoms - capabilities.atoms, key=lambda a: a.name)]
        for kind_set in self.kinds:
            advertised = _advertised_for(kind_set, capabilities)
            if advertised is None or not advertised.contains(kind_set):
                gaps.append(f"{type(kind_set).__name__}({_kind_names(kind_set)})")
        return gaps
atoms = frozenset() class-attribute instance-attribute
hint = None class-attribute instance-attribute
kinds = () class-attribute instance-attribute
missing(capabilities)

Names of the atoms and kind sets this alternative needs but capabilities lacks.

Source code in steerability/algorithms/core/execution/contracts.py
205
206
207
208
209
210
211
212
def missing(self, capabilities: BackendCapabilities) -> list[str]:
    """Names of the atoms and kind sets this alternative needs but `capabilities` lacks."""
    gaps = [atom.name for atom in sorted(self.atoms - capabilities.atoms, key=lambda a: a.name)]
    for kind_set in self.kinds:
        advertised = _advertised_for(kind_set, capabilities)
        if advertised is None or not advertised.contains(kind_set):
            gaps.append(f"{type(kind_set).__name__}({_kind_names(kind_set)})")
    return gaps
satisfied_by(capabilities)

Return True when every atom is advertised and every kind set is contained.

Source code in steerability/algorithms/core/execution/contracts.py
195
196
197
198
199
200
201
202
203
def satisfied_by(self, capabilities: BackendCapabilities) -> bool:
    """Return True when every atom is advertised and every kind set is contained."""
    if not self.atoms <= capabilities.atoms:
        return False
    for kind_set in self.kinds:
        advertised = _advertised_for(kind_set, capabilities)
        if advertised is None or not advertised.contains(kind_set):
            return False
    return True
BackendCapabilities dataclass

A backend's full capability advertisement: atoms plus negotiated kind sets.

Attributes:

Name Type Description
atoms frozenset[Capability]

The advertised Capability atoms.

intervention_kinds InterventionKinds | None

Advertised intervention kinds, present when Capability.INTERVENTION_SPECS is among the atoms.

processor_kinds ProcessorKinds | None

Advertised processor kinds, present when Capability.PER_STEP_LOGIT_SPECS is among the atoms.

capture_kinds CaptureKinds | None

Advertised capture kinds, present when Capability.HIDDEN_CAPTURE is among the atoms.

constraint_kinds ConstraintKinds | None

Advertised constrained-decoding kinds, present when Capability.GUIDED_DECODING is among the atoms.

Source code in steerability/algorithms/core/execution/contracts.py
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
@dataclass(frozen=True, slots=True)
class BackendCapabilities:
    """A backend's full capability advertisement: atoms plus negotiated kind sets.

    Attributes:
        atoms: The advertised `Capability` atoms.
        intervention_kinds: Advertised intervention kinds, present when
            `Capability.INTERVENTION_SPECS` is among the atoms.
        processor_kinds: Advertised processor kinds, present when
            `Capability.PER_STEP_LOGIT_SPECS` is among the atoms.
        capture_kinds: Advertised capture kinds, present when `Capability.HIDDEN_CAPTURE` is
            among the atoms.
        constraint_kinds: Advertised constrained-decoding kinds, present when
            `Capability.GUIDED_DECODING` is among the atoms.
    """

    atoms: frozenset[Capability] = frozenset()
    intervention_kinds: InterventionKinds | None = None
    processor_kinds: ProcessorKinds | None = None
    capture_kinds: CaptureKinds | None = None
    constraint_kinds: ConstraintKinds | None = None
atoms = frozenset() class-attribute instance-attribute
capture_kinds = None class-attribute instance-attribute
constraint_kinds = None class-attribute instance-attribute
intervention_kinds = None class-attribute instance-attribute
processor_kinds = None class-attribute instance-attribute
Capability

Bases: Enum

Distinguishing capability atoms advertised by backends.

Attributes:

Name Type Description
IN_PROCESS_TORCH

The backend exposes the model as a live torch.nn.Module in the client process, so torch hooks, live logits processors, and direct weight access are available. The name refers to this mechanism rather than to process locality.

INTERVENTION_SPECS

The backend executes activation interventions submitted as InterventionSpec payloads. The Hugging Face backend does not advertise this atom, since torch hooks cover every intervention a spec expresses; requirements state the relationship as alternatives.

PER_STEP_LOGIT_SPECS

The backend hosts per-step logit math submitted as ProcessorSpec payloads.

HIDDEN_CAPTURE

The backend serves hidden-state capture through SteeringSession.capture.

BEAM_PROPOSALS

The backend implements beam-search proposal semantics (num_beams with multiple returned sequences).

SERVE_CHECKPOINT

The backend can serve a checkpoint directory produced elsewhere.

SERVE_LORA

The backend can serve a LoRA adapter produced elsewhere.

GUIDED_DECODING

The backend hosts declarative constrained decoding natively, rendered from a ConstraintSource onto its structured-output request parameters. The Hugging Face backend does not advertise this atom, since the in-process arm serves the constraint class through a client-compiled automaton; requirements state the relationship as alternatives.

Source code in steerability/algorithms/core/execution/contracts.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Capability(Enum):
    """Distinguishing capability atoms advertised by backends.

    Attributes:
        IN_PROCESS_TORCH: The backend exposes the model as a live `torch.nn.Module` in the client
            process, so torch hooks, live logits processors, and direct weight access are
            available. The name refers to this mechanism rather than to process locality.
        INTERVENTION_SPECS: The backend executes activation interventions submitted as
            `InterventionSpec` payloads. The Hugging Face backend does not advertise this atom,
            since torch hooks cover every intervention a spec expresses; requirements state the
            relationship as alternatives.
        PER_STEP_LOGIT_SPECS: The backend hosts per-step logit math submitted as `ProcessorSpec`
            payloads.
        HIDDEN_CAPTURE: The backend serves hidden-state capture through `SteeringSession.capture`.
        BEAM_PROPOSALS: The backend implements beam-search proposal semantics (`num_beams` with
            multiple returned sequences).
        SERVE_CHECKPOINT: The backend can serve a checkpoint directory produced elsewhere.
        SERVE_LORA: The backend can serve a LoRA adapter produced elsewhere.
        GUIDED_DECODING: The backend hosts declarative constrained decoding natively, rendered
            from a `ConstraintSource` onto its structured-output request parameters. The
            Hugging Face backend does not advertise this atom, since the in-process arm serves
            the constraint class through a client-compiled automaton; requirements state the
            relationship as alternatives.
    """

    IN_PROCESS_TORCH = "in_process_torch"
    INTERVENTION_SPECS = "intervention_specs"
    PER_STEP_LOGIT_SPECS = "per_step_logit_specs"
    HIDDEN_CAPTURE = "hidden_capture"
    BEAM_PROPOSALS = "beam_proposals"
    SERVE_CHECKPOINT = "serve_checkpoint"
    SERVE_LORA = "serve_lora"
    GUIDED_DECODING = "guided_decoding"
BEAM_PROPOSALS = 'beam_proposals' class-attribute instance-attribute
GUIDED_DECODING = 'guided_decoding' class-attribute instance-attribute
HIDDEN_CAPTURE = 'hidden_capture' class-attribute instance-attribute
INTERVENTION_SPECS = 'intervention_specs' class-attribute instance-attribute
IN_PROCESS_TORCH = 'in_process_torch' class-attribute instance-attribute
PER_STEP_LOGIT_SPECS = 'per_step_logit_specs' class-attribute instance-attribute
SERVE_CHECKPOINT = 'serve_checkpoint' class-attribute instance-attribute
SERVE_LORA = 'serve_lora' class-attribute instance-attribute
CaptureKinds dataclass

Hidden-state capture forms a backend serves, by permanent wire name.

Attributes:

Name Type Description
kinds frozenset[str]

Capture kinds, e.g. {"residual"}.

locations frozenset[str]

Capture locations, e.g. {"layer_output", "layer_input"}.

modes frozenset[str]

Capture modes, e.g. {"all_tokens", "last_token"}.

Source code in steerability/algorithms/core/execution/contracts.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
@dataclass(frozen=True, slots=True)
class CaptureKinds:
    """Hidden-state capture forms a backend serves, by permanent wire name.

    Attributes:
        kinds: Capture kinds, e.g. `{"residual"}`.
        locations: Capture locations, e.g. `{"layer_output", "layer_input"}`.
        modes: Capture modes, e.g. `{"all_tokens", "last_token"}`.
    """

    kinds: frozenset[str] = frozenset()
    locations: frozenset[str] = frozenset()
    modes: frozenset[str] = frozenset()

    def contains(self, required: "CaptureKinds") -> bool:
        """Return True when every required kind name is advertised."""
        return (
            required.kinds <= self.kinds
            and required.locations <= self.locations
            and required.modes <= self.modes
        )
kinds = frozenset() class-attribute instance-attribute
locations = frozenset() class-attribute instance-attribute
modes = frozenset() class-attribute instance-attribute
contains(required)

Return True when every required kind name is advertised.

Source code in steerability/algorithms/core/execution/contracts.py
124
125
126
127
128
129
130
def contains(self, required: "CaptureKinds") -> bool:
    """Return True when every required kind name is advertised."""
    return (
        required.kinds <= self.kinds
        and required.locations <= self.locations
        and required.modes <= self.modes
    )
ConstraintKinds dataclass

Constrained-decoding kinds a backend hosts natively, by declarative kind name.

The kind set is static per backend version (the engine's structured-output surface needs no discovery), e.g. {"json_schema", "regex", "grammar", "choice"}.

Attributes:

Name Type Description
constraints frozenset[str]

Constraint kind names.

Source code in steerability/algorithms/core/execution/contracts.py
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
@dataclass(frozen=True, slots=True)
class ConstraintKinds:
    """Constrained-decoding kinds a backend hosts natively, by declarative kind name.

    The kind set is static per backend version (the engine's structured-output surface needs no
    discovery), e.g. `{"json_schema", "regex", "grammar", "choice"}`.

    Attributes:
        constraints: Constraint kind names.
    """

    constraints: frozenset[str] = frozenset()

    def contains(self, required: "ConstraintKinds") -> bool:
        """Return True when every required kind name is advertised."""
        return required.constraints <= self.constraints
constraints = frozenset() class-attribute instance-attribute
contains(required)

Return True when every required kind name is advertised.

Source code in steerability/algorithms/core/execution/contracts.py
146
147
148
def contains(self, required: "ConstraintKinds") -> bool:
    """Return True when every required kind name is advertised."""
    return required.constraints <= self.constraints
InterventionKinds dataclass

Activation-intervention kinds a backend executes, by permanent wire name.

Wire names mirror toolkit class names (AdditiveTransform serializes as "additive", SumThreshold as "sum_threshold"), so the mapping is definitional rather than maintained. Kind names are permanent and their meanings never change; new behavior is a new kind. Compatibility is set containment on kind names.

Attributes:

Name Type Description
transforms frozenset[str]

Transform kinds, e.g. {"additive", "projection", "rotation", "head_additive"}.

modifiers frozenset[str]

Wrapper-transform kinds, e.g. {"norm_preserving", "alignment_adaptive"}.

scopes frozenset[str]

Token-scope kinds, e.g. {"all", "after_prompt", "last_k", "from_position"}.

readouts frozenset[str]

Gate readout kinds, e.g. {"affine", "cosine", "projected_cosine"}; an ungated op needs none.

rules frozenset[str]

Gate rule kinds, e.g. {"sum_threshold", "per_key_threshold"}.

constraints Mapping[str, str]

Per-kind execution constraints, e.g. {"head_additive": "tensor_parallel_size==1"}. Informational; containment checks ignore this field.

Source code in steerability/algorithms/core/execution/contracts.py
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
@dataclass(frozen=True, slots=True)
class InterventionKinds:
    """Activation-intervention kinds a backend executes, by permanent wire name.

    Wire names mirror toolkit class names (`AdditiveTransform` serializes as `"additive"`,
    `SumThreshold` as `"sum_threshold"`), so the mapping is definitional rather than
    maintained. Kind names are permanent and their meanings never change; new behavior is a
    new kind. Compatibility is set containment on kind names.

    Attributes:
        transforms: Transform kinds, e.g. `{"additive", "projection", "rotation",
            "head_additive"}`.
        modifiers: Wrapper-transform kinds, e.g. `{"norm_preserving", "alignment_adaptive"}`.
        scopes: Token-scope kinds, e.g. `{"all", "after_prompt", "last_k", "from_position"}`.
        readouts: Gate readout kinds, e.g. `{"affine", "cosine", "projected_cosine"}`; an
            ungated op needs none.
        rules: Gate rule kinds, e.g. `{"sum_threshold", "per_key_threshold"}`.
        constraints: Per-kind execution constraints, e.g.
            `{"head_additive": "tensor_parallel_size==1"}`. Informational; containment checks
            ignore this field.
    """

    transforms: frozenset[str] = frozenset()
    modifiers: frozenset[str] = frozenset()
    scopes: frozenset[str] = frozenset()
    readouts: frozenset[str] = frozenset()
    rules: frozenset[str] = frozenset()
    constraints: Mapping[str, str] = field(default_factory=dict)

    def contains(self, required: "InterventionKinds") -> bool:
        """Return True when every required kind name is advertised."""
        return (
            required.transforms <= self.transforms
            and required.modifiers <= self.modifiers
            and required.scopes <= self.scopes
            and required.readouts <= self.readouts
            and required.rules <= self.rules
        )
constraints = field(default_factory=dict) class-attribute instance-attribute
modifiers = frozenset() class-attribute instance-attribute
readouts = frozenset() class-attribute instance-attribute
rules = frozenset() class-attribute instance-attribute
scopes = frozenset() class-attribute instance-attribute
transforms = frozenset() class-attribute instance-attribute
contains(required)

Return True when every required kind name is advertised.

Source code in steerability/algorithms/core/execution/contracts.py
84
85
86
87
88
89
90
91
92
def contains(self, required: "InterventionKinds") -> bool:
    """Return True when every required kind name is advertised."""
    return (
        required.transforms <= self.transforms
        and required.modifiers <= self.modifiers
        and required.scopes <= self.scopes
        and required.readouts <= self.readouts
        and required.rules <= self.rules
    )
ProcessorKinds dataclass

Engine-hosted logit-processor kinds a backend executes, by permanent wire name.

Attributes:

Name Type Description
processors frozenset[str]

Processor kinds, e.g. {"constraint"}.

Source code in steerability/algorithms/core/execution/contracts.py
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
@dataclass(frozen=True, slots=True)
class ProcessorKinds:
    """Engine-hosted logit-processor kinds a backend executes, by permanent wire name.

    Attributes:
        processors: Processor kinds, e.g. `{"constraint"}`.
    """

    processors: frozenset[str] = frozenset()

    def contains(self, required: "ProcessorKinds") -> bool:
        """Return True when every required kind name is advertised."""
        return required.processors <= self.processors
processors = frozenset() class-attribute instance-attribute
contains(required)

Return True when every required kind name is advertised.

Source code in steerability/algorithms/core/execution/contracts.py
105
106
107
def contains(self, required: "ProcessorKinds") -> bool:
    """Return True when every required kind name is advertised."""
    return required.processors <= self.processors
Requirements dataclass

Phase-keyed backend requirements computed by a control instance.

Each phase holds a tuple of Alternatives (a disjunction); an empty tuple requires nothing beyond the session contract, which includes the model layout. The steer phase carries no requirements; a control declares its steer-time model access through steer_access().

Attributes:

Name Type Description
generate tuple[Alternative, ...]

Alternatives for the generate phase.

score tuple[Alternative, ...]

Alternatives for the score phase.

spec_constraints tuple[SpecConstraint, ...]

Backend-configuration predicates, each evaluated against the spec of every phase it names.

Source code in steerability/algorithms/core/execution/contracts.py
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
@dataclass(frozen=True, slots=True)
class Requirements:
    """Phase-keyed backend requirements computed by a control instance.

    Each phase holds a tuple of `Alternative`s (a disjunction); an empty tuple requires nothing
    beyond the session contract, which includes the model layout. The steer phase carries no
    requirements; a control declares its steer-time model access through `steer_access()`.

    Attributes:
        generate: Alternatives for the generate phase.
        score: Alternatives for the score phase.
        spec_constraints: Backend-configuration predicates, each evaluated against the spec of
            every phase it names.
    """

    generate: tuple[Alternative, ...] = ()
    score: tuple[Alternative, ...] = ()
    spec_constraints: tuple[SpecConstraint, ...] = ()

    def for_phase(self, phase: str) -> tuple[Alternative, ...]:
        """The alternatives for `phase` (one of `"generate"`, `"score"`).

        Raises:
            ValueError: If `phase` is not a known phase name.
        """
        if phase not in PHASES:
            raise ValueError(f"Unknown phase {phase!r}; phases are {', '.join(PHASES)}.")
        return getattr(self, phase)
generate = () class-attribute instance-attribute
score = () class-attribute instance-attribute
spec_constraints = () class-attribute instance-attribute
for_phase(phase)

The alternatives for phase (one of "generate", "score").

Raises:

Type Description
ValueError

If phase is not a known phase name.

Source code in steerability/algorithms/core/execution/contracts.py
322
323
324
325
326
327
328
329
330
def for_phase(self, phase: str) -> tuple[Alternative, ...]:
    """The alternatives for `phase` (one of `"generate"`, `"score"`).

    Raises:
        ValueError: If `phase` is not a known phase name.
    """
    if phase not in PHASES:
        raise ValueError(f"Unknown phase {phase!r}; phases are {', '.join(PHASES)}.")
    return getattr(self, phase)
SpecConstraint dataclass

A predicate over a resolved BackendSpec, for backend-configuration facts.

Attributes:

Name Type Description
description str

The unsupported-verdict message shown when the predicate fails. It should name the conflict and a fix.

predicate Callable[[BackendSpec], bool]

Callable evaluated against the phase's BackendSpec; True means satisfied.

phases tuple[str, ...]

Phases whose backend spec the predicate is evaluated against.

Source code in steerability/algorithms/core/execution/contracts.py
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
@dataclass(frozen=True, slots=True)
class SpecConstraint:
    """A predicate over a resolved `BackendSpec`, for backend-configuration facts.

    Attributes:
        description: The unsupported-verdict message shown when the predicate fails. It should
            name the conflict and a fix.
        predicate: Callable evaluated against the phase's `BackendSpec`; True means satisfied.
        phases: Phases whose backend spec the predicate is evaluated against.
    """

    description: str
    predicate: Callable[[BackendSpec], bool]
    phases: tuple[str, ...] = ("generate",)

    def __post_init__(self) -> None:
        unknown = [phase for phase in self.phases if phase not in PHASES]
        if unknown:
            raise ValueError(f"Unknown phases {unknown}; phases are {', '.join(PHASES)}.")
description instance-attribute
phases = ('generate',) class-attribute instance-attribute
predicate instance-attribute
SupportFailure dataclass

One unsupported verdict.

Attributes:

Name Type Description
control str

Class name of the failing control.

phase str

The phase the verdict applies to ("generate" or "score").

message str

Stable, tested message naming the gap and a fix.

Source code in steerability/algorithms/core/execution/contracts.py
357
358
359
360
361
362
363
364
365
366
367
368
369
@dataclass(frozen=True, slots=True)
class SupportFailure:
    """One unsupported verdict.

    Attributes:
        control: Class name of the failing control.
        phase: The phase the verdict applies to (`"generate"` or `"score"`).
        message: Stable, tested message naming the gap and a fix.
    """

    control: str
    phase: str
    message: str
control instance-attribute
message instance-attribute
phase instance-attribute
SupportReport dataclass

The result of evaluating every enabled control against a backend.

Attributes:

Name Type Description
spec BackendSpec

The backend spec the phases were evaluated against.

plan SteerPlan

The deterministic steer plan for this configuration.

failures tuple[SupportFailure, ...]

All unsupported verdicts, in controls-list order then phase order.

Source code in steerability/algorithms/core/execution/contracts.py
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
@dataclass(frozen=True, slots=True)
class SupportReport:
    """The result of evaluating every enabled control against a backend.

    Attributes:
        spec: The backend spec the phases were evaluated against.
        plan: The deterministic steer plan for this configuration.
        failures: All unsupported verdicts, in controls-list order then phase order.
    """

    spec: BackendSpec
    plan: SteerPlan = field(default_factory=SteerPlan)
    failures: tuple[SupportFailure, ...] = ()

    @property
    def ok(self) -> bool:
        """True when no phase of any enabled control is unsupported."""
        return not self.failures

    def failures_for(self, *phases: str) -> tuple[SupportFailure, ...]:
        """The failures whose phase is among `phases`."""
        return tuple(failure for failure in self.failures if failure.phase in phases)

    def supported(self, *phases: str) -> bool:
        """True when no failure falls in any of `phases`."""
        return not self.failures_for(*phases)

    def raise_for(self, *phases: str) -> None:
        """Raise `UnsupportedPipelineError` listing every failing control in `phases`, if any."""
        if not self.supported(*phases):
            raise UnsupportedPipelineError(self, phases)
failures = () class-attribute instance-attribute
ok property

True when no phase of any enabled control is unsupported.

plan = field(default_factory=SteerPlan) class-attribute instance-attribute
spec instance-attribute
failures_for(*phases)

The failures whose phase is among phases.

Source code in steerability/algorithms/core/execution/contracts.py
391
392
393
def failures_for(self, *phases: str) -> tuple[SupportFailure, ...]:
    """The failures whose phase is among `phases`."""
    return tuple(failure for failure in self.failures if failure.phase in phases)
raise_for(*phases)

Raise UnsupportedPipelineError listing every failing control in phases, if any.

Source code in steerability/algorithms/core/execution/contracts.py
399
400
401
402
def raise_for(self, *phases: str) -> None:
    """Raise `UnsupportedPipelineError` listing every failing control in `phases`, if any."""
    if not self.supported(*phases):
        raise UnsupportedPipelineError(self, phases)
supported(*phases)

True when no failure falls in any of phases.

Source code in steerability/algorithms/core/execution/contracts.py
395
396
397
def supported(self, *phases: str) -> bool:
    """True when no failure falls in any of `phases`."""
    return not self.failures_for(*phases)
UnsupportedOperationError

Bases: RuntimeError

Raised when a session receives work it cannot execute on its backend.

Source code in steerability/algorithms/core/execution/contracts.py
353
354
class UnsupportedOperationError(RuntimeError):
    """Raised when a session receives work it cannot execute on its backend."""
UnsupportedPipelineError

Bases: RuntimeError

Raised when an operation targets a backend that does not support the pipeline.

Attributes:

Name Type Description
report

The SupportReport whose failures triggered the error.

Source code in steerability/algorithms/core/execution/contracts.py
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
class UnsupportedPipelineError(RuntimeError):
    """Raised when an operation targets a backend that does not support the pipeline.

    Attributes:
        report: The `SupportReport` whose failures triggered the error.
    """

    def __init__(self, report: "SupportReport", phases: tuple[str, ...]) -> None:
        self.report = report
        failures = report.failures_for(*phases)
        lines = "\n".join(f"- {failure.message}" for failure in failures)
        super().__init__(
            f"Pipeline is unsupported on the configured backends ({len(failures)} unsupported "
            f"requirement(s)):\n{lines}"
        )
report = report instance-attribute
any_of(*alternatives)

Combine alternatives into a disjunction, satisfied by its first satisfied alternative.

Parameters:

Name Type Description Default
*alternatives tuple[Alternative, ...] | Alternative

Alternative instances or tuples of them (as returned by needs).

()

Returns:

Type Description
tuple[Alternative, ...]

The flattened tuple of alternatives.

Source code in steerability/algorithms/core/execution/contracts.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
def any_of(*alternatives: tuple[Alternative, ...] | Alternative) -> tuple[Alternative, ...]:
    """Combine alternatives into a disjunction, satisfied by its first satisfied alternative.

    Args:
        *alternatives: `Alternative` instances or tuples of them (as returned by `needs`).

    Returns:
        The flattened tuple of alternatives.
    """
    flattened: list[Alternative] = []
    for alternative in alternatives:
        if isinstance(alternative, Alternative):
            flattened.append(alternative)
        else:
            flattened.extend(alternative)
    return tuple(flattened)
evaluate_support(controls, spec, capabilities)

Evaluate every enabled control's requirements against a backend.

For each enabled control, control.requirements() is read once and each declared phase is checked against the backend's capabilities. Spec constraints are checked for every phase they name. Controls whose enabled attribute is False are skipped.

Parameters:

Name Type Description Default
controls Iterable[Any]

Control instances, in pipeline order.

required
spec BackendSpec

The backend spec.

required
capabilities BackendCapabilities

Capability advertisement of the backend.

required

Returns:

Type Description
SupportReport

A SupportReport whose failures hold one entry per unsupported (control, phase) pair

SupportReport

and per violated spec constraint.

Source code in steerability/algorithms/core/execution/contracts.py
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
def evaluate_support(
    controls: Iterable[Any],
    spec: BackendSpec,
    capabilities: BackendCapabilities,
) -> SupportReport:
    """Evaluate every enabled control's requirements against a backend.

    For each enabled control, `control.requirements()` is read once and each declared phase is
    checked against the backend's capabilities. Spec constraints are checked for every phase
    they name. Controls whose `enabled` attribute is False are skipped.

    Args:
        controls: Control instances, in pipeline order.
        spec: The backend spec.
        capabilities: Capability advertisement of the backend.

    Returns:
        A `SupportReport` whose `failures` hold one entry per unsupported (control, phase) pair
        and per violated spec constraint.
    """
    failures: list[SupportFailure] = []
    for control in controls:
        if not getattr(control, "enabled", True):
            continue
        control_name = type(control).__name__
        requirements: Requirements = control.requirements()

        for phase in PHASES:
            alternatives = requirements.for_phase(phase)
            if not alternatives:
                continue
            if any(alternative.satisfied_by(capabilities) for alternative in alternatives):
                continue
            failures.append(SupportFailure(
                control=control_name,
                phase=phase,
                message=_phase_failure_message(control_name, phase, spec, requirements, capabilities),
            ))

        for constraint in requirements.spec_constraints:
            for phase in constraint.phases:
                if constraint.predicate(spec):
                    continue
                failures.append(SupportFailure(
                    control=control_name,
                    phase=phase,
                    message=(
                        f"{control_name} is unsupported at {phase} on backend kind "
                        f"'{spec.kind}': {constraint.description}"
                    ),
                ))

    return SupportReport(spec=spec, failures=tuple(failures))
needs(*atoms, kinds=None, hint=None)

Build a single-alternative phase requirement.

Parameters:

Name Type Description Default
*atoms Capability

Capability atoms that must all be advertised.

()
kinds KindSet | tuple[KindSet, ...] | None

One kind set, or a tuple of kind sets, whose names must be contained in the backend's advertisement.

None
hint str | None

Optional fix text for unsupported-verdict messages.

None

Returns:

Type Description
tuple[Alternative, ...]

A one-element tuple of Alternative, directly assignable to a Requirements phase.

Source code in steerability/algorithms/core/execution/contracts.py
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
def needs(
    *atoms: Capability,
    kinds: KindSet | tuple[KindSet, ...] | None = None,
    hint: str | None = None,
) -> tuple[Alternative, ...]:
    """Build a single-alternative phase requirement.

    Args:
        *atoms: Capability atoms that must all be advertised.
        kinds: One kind set, or a tuple of kind sets, whose names must be contained in the
            backend's advertisement.
        hint: Optional fix text for unsupported-verdict messages.

    Returns:
        A one-element tuple of `Alternative`, directly assignable to a `Requirements` phase.
    """
    if kinds is None:
        kind_sets: tuple[KindSet, ...] = ()
    elif isinstance(kinds, tuple):
        kind_sets = kinds
    else:
        kind_sets = (kinds,)
    return (Alternative(atoms=frozenset(atoms), kinds=kind_sets, hint=hint),)

fanout

Per-item seed derivation, bounded fan-out, transport retries, and the partial-batch error.

Shared machinery for request-building sessions. Everything here is backend-agnostic and runs without any optional dependency.

logger = logging.getLogger(__name__) module-attribute
PartialBatchError

Bases: RuntimeError

Raised when some items of a fan-out failed after retries while others succeeded.

Attributes:

Name Type Description
results

The successful per-item results, in item order (ItemResults for generation, per-item score rows for scoring).

failures

(item_index, exception) pairs for the failed items, in item order.

Source code in steerability/algorithms/core/execution/fanout.py
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
class PartialBatchError(RuntimeError):
    """Raised when some items of a fan-out failed after retries while others succeeded.

    Attributes:
        results: The successful per-item results, in item order (`ItemResult`s for generation,
            per-item score rows for scoring).
        failures: `(item_index, exception)` pairs for the failed items, in item order.
    """

    def __init__(
        self,
        results: Sequence[ItemResult] | Sequence[Any],
        failures: Sequence[tuple[int, Exception]],
    ) -> None:
        self.results = tuple(results)
        self.failures = tuple(failures)
        summary = "; ".join(
            f"item {index}: {type(error).__name__}: {error}" for index, error in self.failures
        )
        super().__init__(
            f"{len(self.failures)} of {len(self.results) + len(self.failures)} items failed "
            f"after retries ({summary}). Successful results are on `results`; re-issue the "
            "indices on `failed_indices`."
        )

    @property
    def failed_indices(self) -> tuple[int, ...]:
        """Indices of the failed items, re-issuable as a remainder batch."""
        return tuple(index for index, _ in self.failures)
failed_indices property

Indices of the failed items, re-issuable as a remainder batch.

failures = tuple(failures) instance-attribute
results = tuple(results) instance-attribute
TransportError

Bases: RuntimeError

A transport-level failure (connection, timeout, or server-side 5xx) that is safe to retry.

Application-level rejections (validation errors, unknown parameters) are not transport errors and must not be wrapped in this type.

Source code in steerability/algorithms/core/execution/fanout.py
40
41
42
43
44
45
class TransportError(RuntimeError):
    """A transport-level failure (connection, timeout, or server-side 5xx) that is safe to retry.

    Application-level rejections (validation errors, unknown parameters) are not transport
    errors and must not be wrapped in this type.
    """
derive_item_seed(base_seed, operation_id, item_index)

Derive one item's sampling seed from a base seed, an operation id, and the item index.

The derivation is SHA-256("{base_seed}:{operation_id}:{item_index}") truncated to the first eight bytes (big-endian) and masked to 63 bits, so the result is a stable non-negative integer accepted by every backend sampler. Distinct item indices under one operation yield distinct streams while the whole fan-out stays reproducible from base_seed.

Parameters:

Name Type Description Default
base_seed int

The caller-supplied seed.

required
operation_id str

Identifier of the logical operation (stable across reruns).

required
item_index int

Position of the item in the submitted sequence.

required

Returns:

Type Description
int

The derived seed in [0, 2**63).

Source code in steerability/algorithms/core/execution/fanout.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def derive_item_seed(base_seed: int, operation_id: str, item_index: int) -> int:
    """Derive one item's sampling seed from a base seed, an operation id, and the item index.

    The derivation is `SHA-256("{base_seed}:{operation_id}:{item_index}")` truncated to the
    first eight bytes (big-endian) and masked to 63 bits, so the result is a stable non-negative
    integer accepted by every backend sampler. Distinct item indices under one operation yield
    distinct streams while the whole fan-out stays reproducible from `base_seed`.

    Args:
        base_seed: The caller-supplied seed.
        operation_id: Identifier of the logical operation (stable across reruns).
        item_index: Position of the item in the submitted sequence.

    Returns:
        The derived seed in `[0, 2**63)`.
    """
    digest = hashlib.sha256(f"{base_seed}:{operation_id}:{item_index}".encode("utf-8")).digest()
    return int.from_bytes(digest[:8], "big") & _SEED_MASK
run_bounded(tasks, max_concurrency)

Run tasks concurrently with at most max_concurrency in flight.

Parameters:

Name Type Description Default
tasks Sequence[Callable[[], Any]]

Zero-argument callables, one per item.

required
max_concurrency int

Maximum number of concurrently running tasks (at least 1).

required

Returns:

Type Description
list[Any | Exception]

One entry per task in task order: the task's return value, or the exception it raised.

Source code in steerability/algorithms/core/execution/fanout.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
def run_bounded(
    tasks: Sequence[Callable[[], Any]],
    max_concurrency: int,
) -> list[Any | Exception]:
    """Run `tasks` concurrently with at most `max_concurrency` in flight.

    Args:
        tasks: Zero-argument callables, one per item.
        max_concurrency: Maximum number of concurrently running tasks (at least 1).

    Returns:
        One entry per task in task order: the task's return value, or the exception it raised.
    """
    if not tasks:
        return []
    max_workers = max(1, min(int(max_concurrency), len(tasks)))
    if max_workers == 1:
        results: list[Any | Exception] = []
        for task in tasks:
            try:
                results.append(task())
            except Exception as error:
                results.append(error)
        return results
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = [executor.submit(task) for task in tasks]
        gathered: list[Any | Exception] = []
        for future in futures:
            error = future.exception()
            gathered.append(future.result() if error is None else error)
        return gathered
with_transport_retries(fn, *, max_attempts=3, backoff_base=0.5, sleep=time.sleep)

Call fn, retrying TransportErrors with exponential backoff.

Only TransportError triggers a retry; every other exception propagates immediately, since an application-level rejection will not change on resubmission.

Parameters:

Name Type Description Default
fn Callable[[], Any]

Zero-argument callable issuing one request.

required
max_attempts int

Total attempts including the first.

3
backoff_base float

Sleep before attempt k (1-based retries) is backoff_base * 2**(k-1).

0.5
sleep Callable[[float], None]

Sleep function (injectable for tests).

sleep

Returns:

Type Description
Any

fn()'s return value.

Raises:

Type Description
TransportError

The last attempt's error when every attempt failed.

Source code in steerability/algorithms/core/execution/fanout.py
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
def with_transport_retries(
    fn: Callable[[], Any],
    *,
    max_attempts: int = 3,
    backoff_base: float = 0.5,
    sleep: Callable[[float], None] = time.sleep,
) -> Any:
    """Call `fn`, retrying `TransportError`s with exponential backoff.

    Only `TransportError` triggers a retry; every other exception propagates immediately, since
    an application-level rejection will not change on resubmission.

    Args:
        fn: Zero-argument callable issuing one request.
        max_attempts: Total attempts including the first.
        backoff_base: Sleep before attempt `k` (1-based retries) is `backoff_base * 2**(k-1)`.
        sleep: Sleep function (injectable for tests).

    Returns:
        `fn()`'s return value.

    Raises:
        TransportError: The last attempt's error when every attempt failed.
    """
    attempt = 0
    while True:
        try:
            return fn()
        except TransportError as error:
            attempt += 1
            if attempt >= max_attempts:
                raise
            delay = backoff_base * (2 ** (attempt - 1))
            logger.debug("Transport error (%s); retrying in %.2fs.", error, delay)
            sleep(delay)

params

Normalized generation parameters with one rendering rule per backend family.

LOWERABLE_PARAM_NAMES = ('stop_strings', 'stop_token_ids', 'max_new_tokens', 'min_new_tokens') module-attribute
NORMALIZED_PARAM_NAMES = ('max_new_tokens', 'min_new_tokens', 'temperature', 'top_p', 'top_k', 'greedy', 'n', 'repetition_penalty', 'seed', 'seed_scope', 'stop_strings', 'stop_token_ids') module-attribute
SEED_SCOPES = ('item', 'dispatch') module-attribute
GenerationParams dataclass

The sampling-facing subset of generation parameters, normalized across backends.

Each backend family owns one rendering rule. In-process, the normalized fields render onto model.generate names and every key in extra passes through untouched. On API backends the normalized table is exhaustive and unmapped parameters raise, so extra is rejected there.

Attributes:

Name Type Description
max_new_tokens int | None

Maximum number of new tokens.

min_new_tokens int | None

Minimum number of new tokens.

temperature float | None

Sampling temperature.

top_p float | None

Nucleus-sampling probability mass.

top_k int | None

Top-k sampling cutoff.

greedy bool | None

True forces greedy decoding, False forces sampling, None leaves the backend default.

n int | None

Number of returned candidates per prompt.

repetition_penalty float | None

Repetition penalty.

seed int | None

Sampling seed. In-process it renders as a fork_rng-scoped manual_seed around the item's decode; on vLLM it maps to the request seed. Sessions derive a distinct per-item seed from this value when an item carries no seed of its own.

seed_scope Literal['item', 'dispatch']

How a call-level seed maps onto the items of one dispatch. "item" derives one seed per item from the operation id and the item index, so an item's stream is independent of its batch-mates; on the in-process backend a multi-item dispatch then decodes one item at a time. "dispatch" derives one seed for the whole dispatch and decodes every item in one batched pass; the call is reproducible as a whole (the same items in the same order under the same seed reproduce), and an individual item is not reproducible independently of batch composition. Ignored when seed is None. An item carrying its own seed is honored as given under either scope. On vLLM backends the scope is inert, since per-request seeds execute inside one engine batch under either value.

stop_strings tuple[str, ...]

Stop strings, composed by the session as stop rules on both backend families. Token ids are returned as generated; the pipeline truncates decoded text at the first stop-string occurrence.

stop_token_ids tuple[int, ...]

Token ids that halt a row once its last generated token is one of them, in addition to the tokenizer's EOS.

extra Mapping[str, Any]

Additional keyword arguments passed through unmapped on the in-process arm. A normalized field always takes precedence over a same-named key in extra.

Raises:

Type Description
ValueError

If min_new_tokens exceeds max_new_tokens when both are set.

Source code in steerability/algorithms/core/execution/params.py
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
@dataclass(frozen=True, slots=True)
class GenerationParams:
    """The sampling-facing subset of generation parameters, normalized across backends.

    Each backend family owns one rendering rule. In-process, the normalized fields render onto
    `model.generate` names and every key in `extra` passes through untouched. On API backends
    the normalized table is exhaustive and unmapped parameters raise, so `extra` is rejected
    there.

    Attributes:
        max_new_tokens: Maximum number of new tokens.
        min_new_tokens: Minimum number of new tokens.
        temperature: Sampling temperature.
        top_p: Nucleus-sampling probability mass.
        top_k: Top-k sampling cutoff.
        greedy: True forces greedy decoding, False forces sampling, None leaves the backend
            default.
        n: Number of returned candidates per prompt.
        repetition_penalty: Repetition penalty.
        seed: Sampling seed. In-process it renders as a `fork_rng`-scoped `manual_seed` around
            the item's decode; on vLLM it maps to the request seed. Sessions derive a distinct
            per-item seed from this value when an item carries no seed of its own.
        seed_scope: How a call-level `seed` maps onto the items of one dispatch. `"item"` derives
            one seed per item from the operation id and the item index, so an item's stream is
            independent of its batch-mates; on the in-process backend a multi-item dispatch then
            decodes one item at a time. `"dispatch"` derives one seed for the whole dispatch and
            decodes every item in one batched pass; the call is reproducible as a whole (the same
            items in the same order under the same seed reproduce), and an individual item is not
            reproducible independently of batch composition. Ignored when `seed` is None. An item
            carrying its own `seed` is honored as given under either scope. On vLLM backends the
            scope is inert, since per-request seeds execute inside one engine batch under either
            value.
        stop_strings: Stop strings, composed by the session as stop rules on both backend
            families. Token ids are returned as generated; the pipeline truncates decoded text
            at the first stop-string occurrence.
        stop_token_ids: Token ids that halt a row once its last generated token is one of them,
            in addition to the tokenizer's EOS.
        extra: Additional keyword arguments passed through unmapped on the in-process arm. A
            normalized field always takes precedence over a same-named key in `extra`.

    Raises:
        ValueError: If `min_new_tokens` exceeds `max_new_tokens` when both are set.
    """

    max_new_tokens: int | None = None
    min_new_tokens: int | None = None
    temperature: float | None = None
    top_p: float | None = None
    top_k: int | None = None
    greedy: bool | None = None
    n: int | None = None
    repetition_penalty: float | None = None
    seed: int | None = None
    seed_scope: Literal["item", "dispatch"] = "item"
    stop_strings: tuple[str, ...] = ()
    stop_token_ids: tuple[int, ...] = ()
    extra: Mapping[str, Any] = field(default_factory=dict)

    def __post_init__(self) -> None:
        if isinstance(self.stop_strings, str):
            object.__setattr__(self, "stop_strings", (self.stop_strings,))
        else:
            object.__setattr__(self, "stop_strings", tuple(self.stop_strings))
        object.__setattr__(self, "stop_token_ids", tuple(int(i) for i in self.stop_token_ids))
        if self.seed_scope not in SEED_SCOPES:
            raise ValueError(f"seed_scope must be one of {SEED_SCOPES}; got {self.seed_scope!r}.")
        if (
            self.min_new_tokens is not None
            and self.max_new_tokens is not None
            and self.min_new_tokens > self.max_new_tokens
        ):
            raise ValueError(
                f"min_new_tokens={self.min_new_tokens} exceeds max_new_tokens={self.max_new_tokens}; the length "
                "bounds are jointly unsatisfiable. Control contributions only tighten bounds, so lower "
                "min_new_tokens or loosen the tightened max_new_tokens."
            )

    @classmethod
    def from_gen_kwargs(cls, **gen_kwargs: Any) -> "GenerationParams":
        """Split keyword arguments into normalized fields and pass-through extras.

        `do_sample` maps onto `greedy` (inverted) and `num_return_sequences` onto `n`; keys named
        exactly like a normalized field bind to it; everything else lands in `extra`.

        Args:
            **gen_kwargs: Generation keyword arguments in `model.generate` vocabulary.

        Returns:
            The normalized `GenerationParams`.
        """
        normalized: dict[str, Any] = {}
        if "do_sample" in gen_kwargs:
            normalized["greedy"] = not gen_kwargs.pop("do_sample")
        if "num_return_sequences" in gen_kwargs:
            normalized["n"] = gen_kwargs.pop("num_return_sequences")
        for name in NORMALIZED_PARAM_NAMES:
            if name in gen_kwargs:
                normalized[name] = gen_kwargs.pop(name)
        return cls(**normalized, extra=gen_kwargs)

    def to_gen_kwargs(self) -> dict[str, Any]:
        """Render the parameters back into `model.generate`-vocabulary keyword arguments.

        This inverts `from_gen_kwargs`, so `greedy` renders as `do_sample` (inverted), `n` as
        `num_return_sequences`, the stop fields and `seed` keep their normalized names,
        `seed_scope` renders only when it is not the default `"item"`, and `extra` merges
        underneath the normalized fields.

        Returns:
            The keyword arguments; `from_gen_kwargs(**params.to_gen_kwargs())` reproduces
            `params`.
        """
        gen_kwargs: dict[str, Any] = dict(self.extra)
        if self.max_new_tokens is not None:
            gen_kwargs["max_new_tokens"] = self.max_new_tokens
        if self.min_new_tokens is not None:
            gen_kwargs["min_new_tokens"] = self.min_new_tokens
        if self.temperature is not None:
            gen_kwargs["temperature"] = self.temperature
        if self.top_p is not None:
            gen_kwargs["top_p"] = self.top_p
        if self.top_k is not None:
            gen_kwargs["top_k"] = self.top_k
        if self.greedy is not None:
            gen_kwargs["do_sample"] = not self.greedy
        if self.n is not None:
            gen_kwargs["num_return_sequences"] = self.n
        if self.repetition_penalty is not None:
            gen_kwargs["repetition_penalty"] = self.repetition_penalty
        if self.seed is not None:
            gen_kwargs["seed"] = self.seed
        if self.seed_scope != "item":
            gen_kwargs["seed_scope"] = self.seed_scope
        if self.stop_strings:
            gen_kwargs["stop_strings"] = self.stop_strings
        if self.stop_token_ids:
            gen_kwargs["stop_token_ids"] = self.stop_token_ids
        return gen_kwargs
extra = field(default_factory=dict) class-attribute instance-attribute
greedy = None class-attribute instance-attribute
max_new_tokens = None class-attribute instance-attribute
min_new_tokens = None class-attribute instance-attribute
n = None class-attribute instance-attribute
repetition_penalty = None class-attribute instance-attribute
seed = None class-attribute instance-attribute
seed_scope = 'item' class-attribute instance-attribute
stop_strings = () class-attribute instance-attribute
stop_token_ids = () class-attribute instance-attribute
temperature = None class-attribute instance-attribute
top_k = None class-attribute instance-attribute
top_p = None class-attribute instance-attribute
from_gen_kwargs(**gen_kwargs) classmethod

Split keyword arguments into normalized fields and pass-through extras.

do_sample maps onto greedy (inverted) and num_return_sequences onto n; keys named exactly like a normalized field bind to it; everything else lands in extra.

Parameters:

Name Type Description Default
**gen_kwargs Any

Generation keyword arguments in model.generate vocabulary.

{}

Returns:

Type Description
GenerationParams

The normalized GenerationParams.

Source code in steerability/algorithms/core/execution/params.py
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
@classmethod
def from_gen_kwargs(cls, **gen_kwargs: Any) -> "GenerationParams":
    """Split keyword arguments into normalized fields and pass-through extras.

    `do_sample` maps onto `greedy` (inverted) and `num_return_sequences` onto `n`; keys named
    exactly like a normalized field bind to it; everything else lands in `extra`.

    Args:
        **gen_kwargs: Generation keyword arguments in `model.generate` vocabulary.

    Returns:
        The normalized `GenerationParams`.
    """
    normalized: dict[str, Any] = {}
    if "do_sample" in gen_kwargs:
        normalized["greedy"] = not gen_kwargs.pop("do_sample")
    if "num_return_sequences" in gen_kwargs:
        normalized["n"] = gen_kwargs.pop("num_return_sequences")
    for name in NORMALIZED_PARAM_NAMES:
        if name in gen_kwargs:
            normalized[name] = gen_kwargs.pop(name)
    return cls(**normalized, extra=gen_kwargs)
to_gen_kwargs()

Render the parameters back into model.generate-vocabulary keyword arguments.

This inverts from_gen_kwargs, so greedy renders as do_sample (inverted), n as num_return_sequences, the stop fields and seed keep their normalized names, seed_scope renders only when it is not the default "item", and extra merges underneath the normalized fields.

Returns:

Type Description
dict[str, Any]

The keyword arguments; from_gen_kwargs(**params.to_gen_kwargs()) reproduces

dict[str, Any]

params.

Source code in steerability/algorithms/core/execution/params.py
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
def to_gen_kwargs(self) -> dict[str, Any]:
    """Render the parameters back into `model.generate`-vocabulary keyword arguments.

    This inverts `from_gen_kwargs`, so `greedy` renders as `do_sample` (inverted), `n` as
    `num_return_sequences`, the stop fields and `seed` keep their normalized names,
    `seed_scope` renders only when it is not the default `"item"`, and `extra` merges
    underneath the normalized fields.

    Returns:
        The keyword arguments; `from_gen_kwargs(**params.to_gen_kwargs())` reproduces
        `params`.
    """
    gen_kwargs: dict[str, Any] = dict(self.extra)
    if self.max_new_tokens is not None:
        gen_kwargs["max_new_tokens"] = self.max_new_tokens
    if self.min_new_tokens is not None:
        gen_kwargs["min_new_tokens"] = self.min_new_tokens
    if self.temperature is not None:
        gen_kwargs["temperature"] = self.temperature
    if self.top_p is not None:
        gen_kwargs["top_p"] = self.top_p
    if self.top_k is not None:
        gen_kwargs["top_k"] = self.top_k
    if self.greedy is not None:
        gen_kwargs["do_sample"] = not self.greedy
    if self.n is not None:
        gen_kwargs["num_return_sequences"] = self.n
    if self.repetition_penalty is not None:
        gen_kwargs["repetition_penalty"] = self.repetition_penalty
    if self.seed is not None:
        gen_kwargs["seed"] = self.seed
    if self.seed_scope != "item":
        gen_kwargs["seed_scope"] = self.seed_scope
    if self.stop_strings:
        gen_kwargs["stop_strings"] = self.stop_strings
    if self.stop_token_ids:
        gen_kwargs["stop_token_ids"] = self.stop_token_ids
    return gen_kwargs
merge_lowered_params(params, contribution)

Merge one control's sampling-expressible contribution into params.

Stop strings and stop token ids union with the caller's (caller entries first, duplicates dropped); max_new_tokens takes the minimum and min_new_tokens the maximum of the present values, so a control can only tighten the caller's bounds.

Parameters:

Name Type Description Default
params GenerationParams

The caller-derived parameters.

required
contribution Mapping[str, Any]

Mapping over a subset of stop_strings, stop_token_ids, max_new_tokens, and min_new_tokens.

required

Returns:

Type Description
GenerationParams

The merged GenerationParams.

Raises:

Type Description
ValueError

If contribution carries a key outside the lowerable set, or if the tightened bounds cross (min_new_tokens exceeds max_new_tokens), raised on construction of the merged instance.

Source code in steerability/algorithms/core/execution/params.py
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
def merge_lowered_params(params: GenerationParams, contribution: Mapping[str, Any]) -> GenerationParams:
    """Merge one control's sampling-expressible contribution into `params`.

    Stop strings and stop token ids union with the caller's (caller entries first, duplicates
    dropped); `max_new_tokens` takes the minimum and `min_new_tokens` the maximum of the present
    values, so a control can only tighten the caller's bounds.

    Args:
        params: The caller-derived parameters.
        contribution: Mapping over a subset of `stop_strings`, `stop_token_ids`,
            `max_new_tokens`, and `min_new_tokens`.

    Returns:
        The merged `GenerationParams`.

    Raises:
        ValueError: If `contribution` carries a key outside the lowerable set, or if the tightened
            bounds cross (`min_new_tokens` exceeds `max_new_tokens`), raised on construction of the
            merged instance.
    """
    unknown = [key for key in contribution if key not in LOWERABLE_PARAM_NAMES]
    if unknown:
        raise ValueError(
            f"Control contributed non-lowerable generation parameter(s) {sorted(unknown)}; "
            f"lowerable parameters are {', '.join(LOWERABLE_PARAM_NAMES)}."
        )

    updates: dict[str, Any] = {}
    stop_strings = contribution.get("stop_strings")
    if stop_strings:
        if isinstance(stop_strings, str):
            stop_strings = (stop_strings,)
        merged = list(params.stop_strings)
        merged.extend(text for text in stop_strings if text not in merged)
        updates["stop_strings"] = tuple(merged)
    stop_token_ids = contribution.get("stop_token_ids")
    if stop_token_ids:
        merged_ids = list(params.stop_token_ids)
        merged_ids.extend(int(i) for i in stop_token_ids if int(i) not in merged_ids)
        updates["stop_token_ids"] = tuple(merged_ids)
    max_new = contribution.get("max_new_tokens")
    if max_new is not None:
        updates["max_new_tokens"] = (
            max_new if params.max_new_tokens is None else min(params.max_new_tokens, max_new)
        )
    min_new = contribution.get("min_new_tokens")
    if min_new is not None:
        updates["min_new_tokens"] = (
            min_new if params.min_new_tokens is None else max(params.min_new_tokens, min_new)
        )
    if not updates:
        return params
    return replace(params, **updates)

payloads

Payload types crossing the pipeline/backend seam.

Structural model facts, prepared prompts, steer-time artifacts, declarative constraint sources, serialized interventions and processors, and the per-item units of session work with the per-category control contributions they carry. A field on an item holds either an artifact, named for what it is (prompt, ref_output_ids, seed), or the per-call contributions of one control category, named <category>_entries. An entry is one enabled control's contribution for this call, in controls-list order, in whichever representation the session consumes. An item never holds a control object.

Artifact = ModelArtifact | CheckpointArtifact | LoRAArtifact module-attribute
CONSTRAINT_KINDS = ('json_schema', 'regex', 'grammar', 'choice') module-attribute
OutputControlEntry = StackEntry | ProcessorSpecEntry | ConstraintEntry module-attribute
StateControlEntry = HookEntry | InterventionEntry module-attribute
ArtifactProvenance dataclass

Identity of the side that produced an artifact.

Attributes:

Name Type Description
backend_spec_hash str | None

BackendSpec.spec_hash of the producing backend.

model_fingerprint str | None

Fingerprint of the producing model.

tokenizer_fingerprint str | None

Fingerprint of the producing tokenizer and chat template.

Source code in steerability/algorithms/core/execution/payloads.py
112
113
114
115
116
117
118
119
120
121
122
123
124
@dataclass(frozen=True, slots=True)
class ArtifactProvenance:
    """Identity of the side that produced an artifact.

    Attributes:
        backend_spec_hash: `BackendSpec.spec_hash` of the producing backend.
        model_fingerprint: Fingerprint of the producing model.
        tokenizer_fingerprint: Fingerprint of the producing tokenizer and chat template.
    """

    backend_spec_hash: str | None = None
    model_fingerprint: str | None = None
    tokenizer_fingerprint: str | None = None
backend_spec_hash = None class-attribute instance-attribute
model_fingerprint = None class-attribute instance-attribute
tokenizer_fingerprint = None class-attribute instance-attribute
CaptureResult dataclass

Hidden states captured by SteeringSession.capture.

Attributes:

Name Type Description
hidden Mapping[int, Tensor]

Tensors keyed by 0-based layer id. Shape [N, T, H] in "all_tokens" mode and [N, H] in "last_token" mode, on CPU, in the model's native dtype.

attention_mask Tensor

Mask of shape [N, T] matching the captured prompts, on CPU.

mode str

The capture mode the tensors were produced under.

location str

The capture location ("layer_output" or "layer_input").

Source code in steerability/algorithms/core/execution/payloads.py
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
@dataclass(frozen=True, slots=True, eq=False)
class CaptureResult:
    """Hidden states captured by `SteeringSession.capture`.

    Attributes:
        hidden: Tensors keyed by 0-based layer id. Shape `[N, T, H]` in `"all_tokens"` mode and
            `[N, H]` in `"last_token"` mode, on CPU, in the model's native dtype.
        attention_mask: Mask of shape `[N, T]` matching the captured prompts, on CPU.
        mode: The capture mode the tensors were produced under.
        location: The capture location (`"layer_output"` or `"layer_input"`).
    """

    hidden: Mapping[int, torch.Tensor]
    attention_mask: torch.Tensor
    mode: str
    location: str
attention_mask instance-attribute
hidden instance-attribute
location instance-attribute
mode instance-attribute
CheckpointArtifact dataclass

A checkpoint directory handed across the role boundary; consuming it requires Capability.SERVE_CHECKPOINT.

Attributes:

Name Type Description
path str

Checkpoint directory path.

provenance ArtifactProvenance

Identity of the producing side.

Source code in steerability/algorithms/core/execution/payloads.py
141
142
143
144
145
146
147
148
149
150
151
152
@dataclass(frozen=True, slots=True)
class CheckpointArtifact:
    """A checkpoint directory handed across the role boundary; consuming it requires
    `Capability.SERVE_CHECKPOINT`.

    Attributes:
        path: Checkpoint directory path.
        provenance: Identity of the producing side.
    """

    path: str
    provenance: ArtifactProvenance = field(default_factory=ArtifactProvenance)
path instance-attribute
provenance = field(default_factory=ArtifactProvenance) class-attribute instance-attribute
ConstraintEntry dataclass

An output control's contribution as a declarative constrained-decoding source.

Consumed by backends advertising Capability.GUIDED_DECODING, rendered onto the engine's native structured-output request parameters in place of the control's live processor.

Attributes:

Name Type Description
source ConstraintSource

The declarative constraint.

Source code in steerability/algorithms/core/execution/payloads.py
508
509
510
511
512
513
514
515
516
517
518
519
@dataclass(frozen=True, slots=True)
class ConstraintEntry:
    """An output control's contribution as a declarative constrained-decoding source.

    Consumed by backends advertising `Capability.GUIDED_DECODING`, rendered onto the engine's
    native structured-output request parameters in place of the control's live processor.

    Attributes:
        source: The declarative constraint.
    """

    source: ConstraintSource
source instance-attribute
ConstraintSource dataclass

A declarative constrained-decoding specification.

The portable form of the constraint class: one source renders per execution arm, compiled into a client-side automaton in process and onto the engine's native structured-output request parameters on vLLM backends.

Attributes:

Name Type Description
kind Literal['json_schema', 'regex', 'grammar', 'choice']

The constraint kind: "json_schema", "regex", "grammar" (EBNF), or "choice".

value str | Mapping | Sequence[str]

The constraint payload: a schema string or mapping for "json_schema", a pattern string for "regex", a grammar string for "grammar", or a sequence of candidate strings for "choice".

Source code in steerability/algorithms/core/execution/payloads.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@dataclass(frozen=True, slots=True)
class ConstraintSource:
    """A declarative constrained-decoding specification.

    The portable form of the constraint class: one source renders per execution arm, compiled
    into a client-side automaton in process and onto the engine's native structured-output
    request parameters on vLLM backends.

    Attributes:
        kind: The constraint kind: `"json_schema"`, `"regex"`, `"grammar"` (EBNF), or
            `"choice"`.
        value: The constraint payload: a schema string or mapping for `"json_schema"`, a
            pattern string for `"regex"`, a grammar string for `"grammar"`, or a sequence of
            candidate strings for `"choice"`.
    """

    kind: Literal["json_schema", "regex", "grammar", "choice"]
    value: str | Mapping | Sequence[str]

    def __post_init__(self) -> None:
        if self.kind not in CONSTRAINT_KINDS:
            raise ValueError(
                f"Unknown constraint kind {self.kind!r}; kinds are {', '.join(CONSTRAINT_KINDS)}."
            )
        if self.kind == "json_schema":
            if not isinstance(self.value, (str, Mapping)):
                raise TypeError("A json_schema constraint takes a schema string or mapping.")
        elif self.kind in ("regex", "grammar"):
            if not isinstance(self.value, str):
                raise TypeError(f"A {self.kind} constraint takes a string.")
        else:
            if isinstance(self.value, str) or not isinstance(self.value, Sequence) or not self.value:
                raise TypeError("A choice constraint takes a non-empty sequence of strings.")
            if not all(isinstance(item, str) for item in self.value):
                raise TypeError("A choice constraint takes a non-empty sequence of strings.")
            object.__setattr__(self, "value", tuple(self.value))
kind instance-attribute
value instance-attribute
GenerationItem dataclass

One prompt's unit of generation work.

Input controls have no entry because their contribution is already folded into prompt; structural controls have none because they contribute at steer time through artifacts.

Attributes:

Name Type Description
prompt PreparedPrompt

The prepared prompt.

state_entries tuple[StateControlEntry, ...]

Enabled state controls' contributions, in controls-list order.

output_entries tuple[OutputControlEntry, ...]

Enabled output controls' contributions, in controls-list order.

seed int | None

Per-item sampling seed, or None for unseeded operation.

Source code in steerability/algorithms/core/execution/payloads.py
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
@dataclass(frozen=True, slots=True, eq=False)
class GenerationItem:
    """One prompt's unit of generation work.

    Input controls have no entry because their contribution is already folded into `prompt`;
    structural controls have none because they contribute at steer time through artifacts.

    Attributes:
        prompt: The prepared prompt.
        state_entries: Enabled state controls' contributions, in controls-list order.
        output_entries: Enabled output controls' contributions, in controls-list order.
        seed: Per-item sampling seed, or None for unseeded operation.
    """

    prompt: PreparedPrompt
    state_entries: tuple[StateControlEntry, ...] = ()
    output_entries: tuple[OutputControlEntry, ...] = ()
    seed: int | None = None
output_entries = () class-attribute instance-attribute
prompt instance-attribute
seed = None class-attribute instance-attribute
state_entries = () class-attribute instance-attribute
HookEntry dataclass

One state control's torch-hook contribution, consumed by in-process sessions.

Attributes:

Name Type Description
hooks Mapping[str, list]

Hook specifications keyed by phase ("pre", "forward", "backward"), as returned by StateControl.get_hooks.

Source code in steerability/algorithms/core/execution/payloads.py
467
468
469
470
471
472
473
474
475
476
@dataclass(frozen=True, slots=True, eq=False)
class HookEntry:
    """One state control's torch-hook contribution, consumed by in-process sessions.

    Attributes:
        hooks: Hook specifications keyed by phase (`"pre"`, `"forward"`, `"backward"`), as
            returned by `StateControl.get_hooks`.
    """

    hooks: Mapping[str, list]
hooks instance-attribute
InterventionEntry dataclass

One state control's intervention-spec contribution, consumed by intervention-capable backends.

Attributes:

Name Type Description
spec InterventionSpec

The serialized intervention.

Source code in steerability/algorithms/core/execution/payloads.py
479
480
481
482
483
484
485
486
487
488
@dataclass(frozen=True, slots=True)
class InterventionEntry:
    """One state control's intervention-spec contribution, consumed by intervention-capable
    backends.

    Attributes:
        spec: The serialized intervention.
    """

    spec: InterventionSpec
spec instance-attribute
InterventionSpec dataclass

A serialized activation intervention for intervention-capable backends.

Each op names its target layers, a transform (kind, scalar parameters, tensor payloads by artifact reference, and an ordered modifier list), a token scope, and an optional gate. Kind names are the advertised wire names; a worker rejects a spec containing a kind or field it does not list.

Attributes:

Name Type Description
ops tuple[Mapping[str, Any], ...]

The intervention ops, each a mapping with keys "layers", "transform", "scope", and "gate".

artifacts Mapping[str, Mapping[str, Any]]

Tensor payloads keyed by the content-addressed artifact ids the ops reference, each a mapping from tensor name to a float32 contiguous CPU tensor. Sessions materialize these into the registry the serving engine reads before submission. Excluded from equality, the wire form, and the canonical form.

Source code in steerability/algorithms/core/execution/payloads.py
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
@dataclass(frozen=True, slots=True)
class InterventionSpec:
    """A serialized activation intervention for intervention-capable backends.

    Each op names its target layers, a transform (kind, scalar parameters, tensor payloads by
    artifact reference, and an ordered modifier list), a token scope, and an optional gate. Kind
    names are the advertised wire names; a worker rejects a spec containing a kind or field it
    does not list.

    Attributes:
        ops: The intervention ops, each a mapping with keys `"layers"`, `"transform"`,
            `"scope"`, and `"gate"`.
        artifacts: Tensor payloads keyed by the content-addressed artifact ids the ops
            reference, each a mapping from tensor name to a float32 contiguous CPU tensor.
            Sessions materialize these into the registry the serving engine reads before
            submission. Excluded from equality, the wire form, and the canonical form.
    """

    ops: tuple[Mapping[str, Any], ...] = ()
    artifacts: Mapping[str, Mapping[str, Any]] = field(default_factory=dict, compare=False)

    def to_wire(self) -> dict[str, Any]:
        """The plain-data wire form, `{"ops": [...]}`, with nested mappings and sequences
        converted to dicts and lists."""
        return _plain({"ops": list(self.ops)})

    def artifact_ids(self) -> tuple[str, ...]:
        """Sorted unique artifact ids referenced anywhere in the ops (transform payloads,
        modifiers, and gate readouts)."""
        found: set[str] = set()
        _collect_artifact_ids(self.to_wire(), found)
        return tuple(sorted(found))

    def required_kinds(self) -> InterventionKinds:
        """The kind names this spec requires a backend to serve, as an `InterventionKinds`.

        Collects transform, modifier, scope, and gate readout/rule kind names from the ops; a
        backend whose negotiated kinds contain them can execute the spec.
        """
        transforms: set[str] = set()
        modifiers: set[str] = set()
        scopes: set[str] = set()
        readouts: set[str] = set()
        rules: set[str] = set()
        for op in self.to_wire()["ops"]:
            transform = op.get("transform", {})
            if "kind" in transform:
                transforms.add(transform["kind"])
            for modifier in transform.get("modifiers", []):
                if "kind" in modifier:
                    modifiers.add(modifier["kind"])
            scope = op.get("scope", {})
            if "kind" in scope:
                scopes.add(scope["kind"])
            gate = op.get("gate")
            if gate is not None:
                readout = gate.get("readout", {})
                if "kind" in readout:
                    readouts.add(readout["kind"])
                rule = gate.get("rule", {})
                if "kind" in rule:
                    rules.add(rule["kind"])
        return InterventionKinds(
            transforms=frozenset(transforms),
            modifiers=frozenset(modifiers),
            scopes=frozenset(scopes),
            readouts=frozenset(readouts),
            rules=frozenset(rules),
        )

    def canonical(self) -> str:
        """The canonical serialization, the form hashed for cache salting and provenance.

        Delegates to `vllm_hook_plugins.core.canonical.canonical_bytes` (sorted keys, compact
        separators, UTF-8), so the toolkit and the plugin agree byte-for-byte on the canonical
        form of a spec.

        Raises:
            ModuleNotFoundError: If `vllm_hook_plugins` is not installed. The message names
                the `steerability[vllm]` extra.
            TypeError: If an op contains a value with no JSON form. Tensors belong in
                artifacts, never inline.
        """
        canonical = require("vllm_hook_plugins.core.canonical")
        return canonical.canonical_bytes(self.to_wire()).decode("utf-8")

    def salt(self) -> str:
        """The reference cache salt for requests carrying this spec.

        Delegates to `vllm_hook_plugins.core.canonical.request_salt` over the wire form and
        the referenced artifact ids. Returns the 64-char lowercase-hex digest.

        Raises:
            ModuleNotFoundError: If `vllm_hook_plugins` is not installed. The message names
                the `steerability[vllm]` extra.
        """
        canonical = require("vllm_hook_plugins.core.canonical")
        return canonical.request_salt(self.to_wire(), list(self.artifact_ids()))
artifacts = field(default_factory=dict, compare=False) class-attribute instance-attribute
ops = () class-attribute instance-attribute
artifact_ids()

Sorted unique artifact ids referenced anywhere in the ops (transform payloads, modifiers, and gate readouts).

Source code in steerability/algorithms/core/execution/payloads.py
337
338
339
340
341
342
def artifact_ids(self) -> tuple[str, ...]:
    """Sorted unique artifact ids referenced anywhere in the ops (transform payloads,
    modifiers, and gate readouts)."""
    found: set[str] = set()
    _collect_artifact_ids(self.to_wire(), found)
    return tuple(sorted(found))
canonical()

The canonical serialization, the form hashed for cache salting and provenance.

Delegates to vllm_hook_plugins.core.canonical.canonical_bytes (sorted keys, compact separators, UTF-8), so the toolkit and the plugin agree byte-for-byte on the canonical form of a spec.

Raises:

Type Description
ModuleNotFoundError

If vllm_hook_plugins is not installed. The message names the steerability[vllm] extra.

TypeError

If an op contains a value with no JSON form. Tensors belong in artifacts, never inline.

Source code in steerability/algorithms/core/execution/payloads.py
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
def canonical(self) -> str:
    """The canonical serialization, the form hashed for cache salting and provenance.

    Delegates to `vllm_hook_plugins.core.canonical.canonical_bytes` (sorted keys, compact
    separators, UTF-8), so the toolkit and the plugin agree byte-for-byte on the canonical
    form of a spec.

    Raises:
        ModuleNotFoundError: If `vllm_hook_plugins` is not installed. The message names
            the `steerability[vllm]` extra.
        TypeError: If an op contains a value with no JSON form. Tensors belong in
            artifacts, never inline.
    """
    canonical = require("vllm_hook_plugins.core.canonical")
    return canonical.canonical_bytes(self.to_wire()).decode("utf-8")
required_kinds()

The kind names this spec requires a backend to serve, as an InterventionKinds.

Collects transform, modifier, scope, and gate readout/rule kind names from the ops; a backend whose negotiated kinds contain them can execute the spec.

Source code in steerability/algorithms/core/execution/payloads.py
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
def required_kinds(self) -> InterventionKinds:
    """The kind names this spec requires a backend to serve, as an `InterventionKinds`.

    Collects transform, modifier, scope, and gate readout/rule kind names from the ops; a
    backend whose negotiated kinds contain them can execute the spec.
    """
    transforms: set[str] = set()
    modifiers: set[str] = set()
    scopes: set[str] = set()
    readouts: set[str] = set()
    rules: set[str] = set()
    for op in self.to_wire()["ops"]:
        transform = op.get("transform", {})
        if "kind" in transform:
            transforms.add(transform["kind"])
        for modifier in transform.get("modifiers", []):
            if "kind" in modifier:
                modifiers.add(modifier["kind"])
        scope = op.get("scope", {})
        if "kind" in scope:
            scopes.add(scope["kind"])
        gate = op.get("gate")
        if gate is not None:
            readout = gate.get("readout", {})
            if "kind" in readout:
                readouts.add(readout["kind"])
            rule = gate.get("rule", {})
            if "kind" in rule:
                rules.add(rule["kind"])
    return InterventionKinds(
        transforms=frozenset(transforms),
        modifiers=frozenset(modifiers),
        scopes=frozenset(scopes),
        readouts=frozenset(readouts),
        rules=frozenset(rules),
    )
salt()

The reference cache salt for requests carrying this spec.

Delegates to vllm_hook_plugins.core.canonical.request_salt over the wire form and the referenced artifact ids. Returns the 64-char lowercase-hex digest.

Raises:

Type Description
ModuleNotFoundError

If vllm_hook_plugins is not installed. The message names the steerability[vllm] extra.

Source code in steerability/algorithms/core/execution/payloads.py
397
398
399
400
401
402
403
404
405
406
407
408
def salt(self) -> str:
    """The reference cache salt for requests carrying this spec.

    Delegates to `vllm_hook_plugins.core.canonical.request_salt` over the wire form and
    the referenced artifact ids. Returns the 64-char lowercase-hex digest.

    Raises:
        ModuleNotFoundError: If `vllm_hook_plugins` is not installed. The message names
            the `steerability[vllm]` extra.
    """
    canonical = require("vllm_hook_plugins.core.canonical")
    return canonical.request_salt(self.to_wire(), list(self.artifact_ids()))
to_wire()

The plain-data wire form, {"ops": [...]}, with nested mappings and sequences converted to dicts and lists.

Source code in steerability/algorithms/core/execution/payloads.py
332
333
334
335
def to_wire(self) -> dict[str, Any]:
    """The plain-data wire form, `{"ops": [...]}`, with nested mappings and sequences
    converted to dicts and lists."""
    return _plain({"ops": list(self.ops)})
ItemResult dataclass

The result of one generation item.

Attributes:

Name Type Description
index int

Position of the item in the submitted sequence.

output Output

The generation record. For n > 1 the record's batch dimension holds the candidates in request order and finish_reason reflects the first candidate.

Source code in steerability/algorithms/core/execution/payloads.py
577
578
579
580
581
582
583
584
585
586
587
588
@dataclass(frozen=True, slots=True, eq=False)
class ItemResult:
    """The result of one generation item.

    Attributes:
        index: Position of the item in the submitted sequence.
        output: The generation record. For `n > 1` the record's batch dimension holds the
            candidates in request order and `finish_reason` reflects the first candidate.
    """

    index: int
    output: Output
index instance-attribute
output instance-attribute
LoRAArtifact dataclass

A LoRA adapter handed across the role boundary; consuming it requires Capability.SERVE_LORA.

Attributes:

Name Type Description
path str

Adapter directory path.

base_model str

Model reference the adapter applies to.

provenance ArtifactProvenance

Identity of the producing side.

Source code in steerability/algorithms/core/execution/payloads.py
155
156
157
158
159
160
161
162
163
164
165
166
167
168
@dataclass(frozen=True, slots=True)
class LoRAArtifact:
    """A LoRA adapter handed across the role boundary; consuming it requires
    `Capability.SERVE_LORA`.

    Attributes:
        path: Adapter directory path.
        base_model: Model reference the adapter applies to.
        provenance: Identity of the producing side.
    """

    path: str
    base_model: str
    provenance: ArtifactProvenance = field(default_factory=ArtifactProvenance)
base_model instance-attribute
path instance-attribute
provenance = field(default_factory=ArtifactProvenance) class-attribute instance-attribute
ModelArtifact dataclass

An in-memory model handed across the role boundary; only the in-process backend can consume it.

Attributes:

Name Type Description
model Any

The loaded model.

provenance ArtifactProvenance

Identity of the producing side.

Source code in steerability/algorithms/core/execution/payloads.py
127
128
129
130
131
132
133
134
135
136
137
138
@dataclass(frozen=True, slots=True, eq=False)
class ModelArtifact:
    """An in-memory model handed across the role boundary; only the in-process backend can
    consume it.

    Attributes:
        model: The loaded model.
        provenance: Identity of the producing side.
    """

    model: Any
    provenance: ArtifactProvenance = field(default_factory=ArtifactProvenance)
model instance-attribute
provenance = field(default_factory=ArtifactProvenance) class-attribute instance-attribute
ModelFacts dataclass

Structural facts about the pipeline model, available without a live module tree.

Layer indices are the canonical coordinates for steer-phase layer selection; module names are an in-process serialization detail resolved only at hook construction time. Client-side tensor preparation uses the layout's dtype, and device placement is handled in process or by the worker rather than at steer time.

Attributes:

Name Type Description
num_layers int

Number of decoder layers.

hidden_size int

Residual-stream width.

num_attention_heads int | None

Number of attention heads, or None when the model config does not state one.

head_dim int | None

Per-head dimension, the config's nominal value (else hidden_size divided by num_attention_heads), or None when neither is derivable. Per-layer geometry can differ from this nominal value (some models alternate head dimensions across layers); consumers needing the actual per-layer geometry read head_geometry.

dtype str

Canonical dtype string, e.g. "bfloat16".

model_fingerprint str

A 16-character hex digest identifying the model weights and config.

model_type str | None

The config's model_type, or None when unknown.

model_ref str | None

The served model reference on engine backends, the loaded model's name_or_path in process, or None when unknown.

Source code in steerability/algorithms/core/execution/payloads.py
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
@dataclass(frozen=True, slots=True)
class ModelFacts:
    """Structural facts about the pipeline model, available without a live module tree.

    Layer indices are the canonical coordinates for steer-phase layer selection; module names
    are an in-process serialization detail resolved only at hook construction time. Client-side
    tensor preparation uses the layout's dtype, and device placement is handled in process or by
    the worker rather than at steer time.


    Attributes:
        num_layers: Number of decoder layers.
        hidden_size: Residual-stream width.
        num_attention_heads: Number of attention heads, or None when the model config does not
            state one.
        head_dim: Per-head dimension, the config's nominal value (else `hidden_size` divided by
            `num_attention_heads`), or None when neither is derivable. Per-layer geometry can
            differ from this nominal value (some models alternate head dimensions across layers);
            consumers needing the actual per-layer geometry read `head_geometry`.
        dtype: Canonical dtype string, e.g. `"bfloat16"`.
        model_fingerprint: A 16-character hex digest identifying the model weights and config.
        model_type: The config's `model_type`, or None when unknown.
        model_ref: The served model reference on engine backends, the loaded model's
            `name_or_path` in process, or None when unknown.
    """

    num_layers: int
    hidden_size: int
    num_attention_heads: int | None
    head_dim: int | None
    dtype: str
    model_fingerprint: str
    model_type: str | None = None
    model_ref: str | None = None
dtype instance-attribute
head_dim instance-attribute
hidden_size instance-attribute
model_fingerprint instance-attribute
model_ref = None class-attribute instance-attribute
model_type = None class-attribute instance-attribute
num_attention_heads instance-attribute
num_layers instance-attribute
PreparedPrompt dataclass

A sum type over messages | text | token_ids for one prompt, plus metadata.

Exactly one of text, messages, or token_ids is set at construction. Tokenization is forced only when a consumer needs token ids (resolve_token_ids); the in-process resolution reproduces the pipeline's tokenization calls, so resolved ids match the early-tokenized path.

Attributes:

Name Type Description
text str | None

A plain-text prompt, or None.

messages tuple[Mapping, ...] | None

One conversation as a tuple of message mappings, or None.

token_ids Tensor | None

Token ids of shape [1, seq_len], or None until resolved.

attention_mask Tensor | None

Attention mask matching token_ids, or None.

is_single bool

Whether the originating call passed a single (non-batched) prompt.

message_handled frozenset[int]

id()s of input controls whose adapt_messages already performed the adaptation for this prompt.

Source code in steerability/algorithms/core/execution/payloads.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
@dataclass(frozen=True, slots=True, eq=False)
class PreparedPrompt:
    """A sum type over `messages | text | token_ids` for one prompt, plus metadata.

    Exactly one of `text`, `messages`, or `token_ids` is set at construction. Tokenization is
    forced only when a consumer needs token ids (`resolve_token_ids`); the in-process resolution
    reproduces the pipeline's tokenization calls, so resolved ids match the early-tokenized path.

    Attributes:
        text: A plain-text prompt, or None.
        messages: One conversation as a tuple of message mappings, or None.
        token_ids: Token ids of shape `[1, seq_len]`, or None until resolved.
        attention_mask: Attention mask matching `token_ids`, or None.
        is_single: Whether the originating call passed a single (non-batched) prompt.
        message_handled: `id()`s of input controls whose `adapt_messages` already performed the
            adaptation for this prompt.
    """

    text: str | None = None
    messages: tuple[Mapping, ...] | None = None
    token_ids: torch.Tensor | None = None
    attention_mask: torch.Tensor | None = None
    is_single: bool = True
    message_handled: frozenset[int] = frozenset()

    def __post_init__(self) -> None:
        sources = [
            name for name, value in (
                ("text", self.text), ("messages", self.messages), ("token_ids", self.token_ids),
            ) if value is not None
        ]
        if len(sources) != 1:
            raise ValueError(
                f"PreparedPrompt requires exactly one of text, messages, or token_ids; got "
                f"{', '.join(sources) or 'none'}."
            )

    @classmethod
    def from_text(cls, text: str) -> "PreparedPrompt":
        """Build a text-form prompt."""
        return cls(text=text)

    @classmethod
    def from_messages(cls, messages: list[Mapping] | tuple[Mapping, ...]) -> "PreparedPrompt":
        """Build a message-form prompt from one conversation."""
        return cls(messages=tuple(messages))

    @classmethod
    def from_token_ids(
        cls,
        token_ids: torch.Tensor | list[int],
        attention_mask: torch.Tensor | None = None,
    ) -> "PreparedPrompt":
        """Build a token-form prompt from a 1-D or `[1, seq_len]` tensor or a `list[int]`.

        Raises:
            ValueError: If `token_ids` carries more than one row; a prompt is one row.
        """
        if isinstance(token_ids, list):
            token_ids = torch.tensor(token_ids, dtype=torch.long)
        if token_ids.ndim == 1:
            token_ids = token_ids.unsqueeze(0)
        if token_ids.ndim != 2 or token_ids.size(0) != 1:
            raise ValueError(
                f"A PreparedPrompt holds one prompt row; got shape {tuple(token_ids.shape)}."
            )
        if attention_mask is not None and attention_mask.ndim == 1:
            attention_mask = attention_mask.unsqueeze(0)
        return cls(token_ids=token_ids, attention_mask=attention_mask)

    def resolve_token_ids(self, tokenizer: "PreTrainedTokenizerBase | None") -> "PreparedPrompt":
        """Return a token-form copy of this prompt, tokenizing text or messages when needed.

        Text prompts tokenize via `tokenizer(...)`; message prompts via
        `tokenizer.apply_chat_template(..., add_generation_prompt=True)`. Both match the
        pipeline's own tokenization calls. A prompt already in token form is returned unchanged.

        Args:
            tokenizer: The pipeline tokenizer.

        Returns:
            A `PreparedPrompt` with `token_ids` (and, when available, `attention_mask`) set.

        Raises:
            ValueError: If tokenization is required but `tokenizer` is None.
        """
        if self.token_ids is not None:
            return self
        if tokenizer is None:
            raise ValueError("A tokenizer is required to resolve this prompt to token ids.")

        if self.text is not None:
            encoded = tokenizer([self.text], return_tensors="pt", padding=True)
            return replace(
                self,
                text=None,
                token_ids=encoded["input_ids"],
                attention_mask=encoded.get("attention_mask"),
            )

        encoded = tokenizer.apply_chat_template(
            [list(self.messages)],
            return_tensors="pt",
            padding=True,
            add_generation_prompt=True,
            return_dict=True,
        )
        input_ids = encoded["input_ids"]
        attention_mask = encoded.get("attention_mask")
        if input_ids.ndim == 1:
            input_ids = input_ids.unsqueeze(0)
            if attention_mask is not None:
                attention_mask = attention_mask.unsqueeze(0)
        return replace(self, messages=None, token_ids=input_ids, attention_mask=attention_mask)
attention_mask = None class-attribute instance-attribute
is_single = True class-attribute instance-attribute
message_handled = frozenset() class-attribute instance-attribute
messages = None class-attribute instance-attribute
text = None class-attribute instance-attribute
token_ids = None class-attribute instance-attribute
from_messages(messages) classmethod

Build a message-form prompt from one conversation.

Source code in steerability/algorithms/core/execution/payloads.py
216
217
218
219
@classmethod
def from_messages(cls, messages: list[Mapping] | tuple[Mapping, ...]) -> "PreparedPrompt":
    """Build a message-form prompt from one conversation."""
    return cls(messages=tuple(messages))
from_text(text) classmethod

Build a text-form prompt.

Source code in steerability/algorithms/core/execution/payloads.py
211
212
213
214
@classmethod
def from_text(cls, text: str) -> "PreparedPrompt":
    """Build a text-form prompt."""
    return cls(text=text)
from_token_ids(token_ids, attention_mask=None) classmethod

Build a token-form prompt from a 1-D or [1, seq_len] tensor or a list[int].

Raises:

Type Description
ValueError

If token_ids carries more than one row; a prompt is one row.

Source code in steerability/algorithms/core/execution/payloads.py
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
@classmethod
def from_token_ids(
    cls,
    token_ids: torch.Tensor | list[int],
    attention_mask: torch.Tensor | None = None,
) -> "PreparedPrompt":
    """Build a token-form prompt from a 1-D or `[1, seq_len]` tensor or a `list[int]`.

    Raises:
        ValueError: If `token_ids` carries more than one row; a prompt is one row.
    """
    if isinstance(token_ids, list):
        token_ids = torch.tensor(token_ids, dtype=torch.long)
    if token_ids.ndim == 1:
        token_ids = token_ids.unsqueeze(0)
    if token_ids.ndim != 2 or token_ids.size(0) != 1:
        raise ValueError(
            f"A PreparedPrompt holds one prompt row; got shape {tuple(token_ids.shape)}."
        )
    if attention_mask is not None and attention_mask.ndim == 1:
        attention_mask = attention_mask.unsqueeze(0)
    return cls(token_ids=token_ids, attention_mask=attention_mask)
resolve_token_ids(tokenizer)

Return a token-form copy of this prompt, tokenizing text or messages when needed.

Text prompts tokenize via tokenizer(...); message prompts via tokenizer.apply_chat_template(..., add_generation_prompt=True). Both match the pipeline's own tokenization calls. A prompt already in token form is returned unchanged.

Parameters:

Name Type Description Default
tokenizer PreTrainedTokenizerBase | None

The pipeline tokenizer.

required

Returns:

Type Description
PreparedPrompt

A PreparedPrompt with token_ids (and, when available, attention_mask) set.

Raises:

Type Description
ValueError

If tokenization is required but tokenizer is None.

Source code in steerability/algorithms/core/execution/payloads.py
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
def resolve_token_ids(self, tokenizer: "PreTrainedTokenizerBase | None") -> "PreparedPrompt":
    """Return a token-form copy of this prompt, tokenizing text or messages when needed.

    Text prompts tokenize via `tokenizer(...)`; message prompts via
    `tokenizer.apply_chat_template(..., add_generation_prompt=True)`. Both match the
    pipeline's own tokenization calls. A prompt already in token form is returned unchanged.

    Args:
        tokenizer: The pipeline tokenizer.

    Returns:
        A `PreparedPrompt` with `token_ids` (and, when available, `attention_mask`) set.

    Raises:
        ValueError: If tokenization is required but `tokenizer` is None.
    """
    if self.token_ids is not None:
        return self
    if tokenizer is None:
        raise ValueError("A tokenizer is required to resolve this prompt to token ids.")

    if self.text is not None:
        encoded = tokenizer([self.text], return_tensors="pt", padding=True)
        return replace(
            self,
            text=None,
            token_ids=encoded["input_ids"],
            attention_mask=encoded.get("attention_mask"),
        )

    encoded = tokenizer.apply_chat_template(
        [list(self.messages)],
        return_tensors="pt",
        padding=True,
        add_generation_prompt=True,
        return_dict=True,
    )
    input_ids = encoded["input_ids"]
    attention_mask = encoded.get("attention_mask")
    if input_ids.ndim == 1:
        input_ids = input_ids.unsqueeze(0)
        if attention_mask is not None:
            attention_mask = attention_mask.unsqueeze(0)
    return replace(self, messages=None, token_ids=input_ids, attention_mask=attention_mask)
ProcessorSpec dataclass

A serialized per-step logit processor for backends advertising engine-hosted logit math.

Attributes:

Name Type Description
kind str

The advertised processor kind name, e.g. "constraint".

params Mapping[str, Any]

Processor parameters.

Source code in steerability/algorithms/core/execution/payloads.py
411
412
413
414
415
416
417
418
419
420
421
@dataclass(frozen=True, slots=True)
class ProcessorSpec:
    """A serialized per-step logit processor for backends advertising engine-hosted logit math.

    Attributes:
        kind: The advertised processor kind name, e.g. `"constraint"`.
        params: Processor parameters.
    """

    kind: str
    params: Mapping[str, Any] = field(default_factory=dict)
kind instance-attribute
params = field(default_factory=dict) class-attribute instance-attribute
ProcessorSpecEntry dataclass

One output control's engine-hosted processor contribution.

Attributes:

Name Type Description
spec ProcessorSpec

The serialized processor.

Source code in steerability/algorithms/core/execution/payloads.py
522
523
524
525
526
527
528
529
530
@dataclass(frozen=True, slots=True)
class ProcessorSpecEntry:
    """One output control's engine-hosted processor contribution.

    Attributes:
        spec: The serialized processor.
    """

    spec: ProcessorSpec
spec instance-attribute
ScoringItem dataclass

One prompt's unit of scoring work (teacher-forced reference tokens).

Only controls participating in scoring contribute entries, and stopping criteria are never applied (there is no loop to stop).

Attributes:

Name Type Description
prompt PreparedPrompt

The prepared prompt.

ref_output_ids Tensor

Reference tokens to score, shape [ref_len] or [1, ref_len].

state_entries tuple[StateControlEntry, ...]

Enabled state controls' contributions, in controls-list order.

output_entries tuple[OutputControlEntry, ...]

Scoring-participant output controls' contributions, in controls-list order.

Source code in steerability/algorithms/core/execution/payloads.py
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
@dataclass(frozen=True, slots=True, eq=False)
class ScoringItem:
    """One prompt's unit of scoring work (teacher-forced reference tokens).

    Only controls participating in scoring contribute entries, and stopping criteria are never
    applied (there is no loop to stop).

    Attributes:
        prompt: The prepared prompt.
        ref_output_ids: Reference tokens to score, shape `[ref_len]` or `[1, ref_len]`.
        state_entries: Enabled state controls' contributions, in controls-list order.
        output_entries: Scoring-participant output controls' contributions, in controls-list
            order.
    """

    prompt: PreparedPrompt
    ref_output_ids: torch.Tensor
    state_entries: tuple[StateControlEntry, ...] = ()
    output_entries: tuple[OutputControlEntry, ...] = ()
output_entries = () class-attribute instance-attribute
prompt instance-attribute
ref_output_ids instance-attribute
state_entries = () class-attribute instance-attribute
StackEntry dataclass

One output control's live processor and criteria contribution, consumed by in-process sessions.

Attributes:

Name Type Description
logits_processors tuple

HF LogitsProcessor-style objects, in contribution order.

stopping_criteria tuple

HF StoppingCriteria-style objects, in contribution order.

Source code in steerability/algorithms/core/execution/payloads.py
494
495
496
497
498
499
500
501
502
503
504
505
@dataclass(frozen=True, slots=True, eq=False)
class StackEntry:
    """One output control's live processor and criteria contribution, consumed by in-process
    sessions.

    Attributes:
        logits_processors: HF `LogitsProcessor`-style objects, in contribution order.
        stopping_criteria: HF `StoppingCriteria`-style objects, in contribution order.
    """

    logits_processors: tuple = ()
    stopping_criteria: tuple = ()
logits_processors = () class-attribute instance-attribute
stopping_criteria = () class-attribute instance-attribute
as_constraint_source(value)

Coerce a mapping with kind and value keys into a ConstraintSource.

Source code in steerability/algorithms/core/execution/payloads.py
65
66
67
68
69
70
71
72
73
def as_constraint_source(value: "ConstraintSource | Mapping[str, Any]") -> ConstraintSource:
    """Coerce a mapping with `kind` and `value` keys into a `ConstraintSource`."""
    if isinstance(value, ConstraintSource):
        return value
    if isinstance(value, Mapping):
        return ConstraintSource(kind=value["kind"], value=value["value"])
    raise TypeError(
        f"Expected a ConstraintSource or a mapping with 'kind' and 'value'; got {type(value).__name__}."
    )
remap_prompt_relative_scopes(spec, anchor)

A rollout copy of spec with prompt-relative scopes rewritten to absolute positions.

Prompt-relative scope kinds are client-side sugar: the worker anchors them at the request's own prompt length, and a driver rollout's request prompt is the accumulated prefix rather than the user prompt. The wire form of a scope inside a driver generation is therefore absolute: after_prompt becomes from_position at anchor (the generation's original prompt boundary). The rewrite changes one scalar per op, so artifact ids are untouched; the cache salt varies with the anchor, which is correct, since differently anchored requests compute different hidden states. The last_k kind is refused: its in-process semantics are relative to each forwarded pass, which no absolute position can reproduce across rollouts.

Parameters:

Name Type Description Default
spec InterventionSpec

The lowered spec.

required
anchor int

The generation's original prompt length, in absolute positions.

required

Returns:

Type Description
InterventionSpec

The rewritten spec (the same object when nothing changed), sharing artifacts.

Raises:

Type Description
ValueError

If an op carries a last_k scope.

Source code in steerability/algorithms/core/execution/payloads.py
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
def remap_prompt_relative_scopes(spec: InterventionSpec, anchor: int) -> InterventionSpec:
    """A rollout copy of `spec` with prompt-relative scopes rewritten to absolute positions.

    Prompt-relative scope kinds are client-side sugar: the worker anchors them at the
    request's own prompt length, and a driver rollout's request prompt is the accumulated
    prefix rather than the user prompt. The wire form of a scope inside a driver generation is
    therefore absolute: `after_prompt` becomes `from_position` at `anchor` (the generation's
    original prompt boundary). The rewrite changes one scalar per op, so artifact ids are
    untouched; the cache salt varies with the anchor, which is correct, since differently
    anchored requests compute different hidden states. The `last_k` kind is refused: its
    in-process semantics are relative to each forwarded pass, which no absolute position can
    reproduce across rollouts.

    Args:
        spec: The lowered spec.
        anchor: The generation's original prompt length, in absolute positions.

    Returns:
        The rewritten spec (the same object when nothing changed), sharing `artifacts`.

    Raises:
        ValueError: If an op carries a `last_k` scope.
    """
    ops = []
    changed = False
    for op in spec.to_wire()["ops"]:
        scope = op.get("scope", {})
        kind = scope.get("kind")
        if kind == "after_prompt":
            op = {**op, "scope": {"kind": "from_position", "position": int(anchor)}}
            changed = True
        elif kind == "last_k":
            raise ValueError(
                "last_k has no absolute rollout form: it is relative to each forwarded pass "
                "in process, which no fixed position reproduces across rollouts; use "
                "from_position, or run this driver on the huggingface backend."
            )
        ops.append(op)
    if not changed:
        return spec
    return InterventionSpec(ops=tuple(ops), artifacts=spec.artifacts)

session_utils

Session-side helpers for steer- and generate-time model access.

session_generate and session_score run one generation or scoring call through a SteeringSession with the model.generate calling convention, so components written against that convention execute on any backend. ScopedSession enforces a control's declared ModelAccess during its steer step, and SessionLM adapts a session into a model-shaped object for helpers that expect one.

ScopedSession

A SteeringSession view scoped to one control's declared steer access.

The pipeline hands each control's steer() a scoped session over the venue session. layout and tokenizer are always available; generate and score delegate at ModelAccess.ROLLOUTS and above; capture delegates at ModelAccess.CAPTURE and above. Calls below the declared rung raise, so undeclared steer-time model contact fails immediately and attributably on every backend. The wrapper exposes no model attribute at any rung; the live module travels only through the model= argument of steer().

Attributes:

Name Type Description
inner

The wrapped venue session.

Source code in steerability/algorithms/core/execution/session_utils.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
class ScopedSession:
    """A `SteeringSession` view scoped to one control's declared steer access.

    The pipeline hands each control's `steer()` a scoped session over the venue session.
    `layout` and `tokenizer` are always available; `generate` and `score` delegate at
    `ModelAccess.ROLLOUTS` and above; `capture` delegates at `ModelAccess.CAPTURE` and above.
    Calls below the declared rung raise, so undeclared steer-time model contact fails
    immediately and attributably on every backend. The wrapper exposes no `model` attribute at
    any rung; the live module travels only through the `model=` argument of `steer()`.

    Attributes:
        inner: The wrapped venue session.
    """

    def __init__(self, inner, control_name: str, access: ModelAccess) -> None:
        self.inner = inner
        self._control_name = control_name
        self._access = access

    @property
    def layout(self):
        """Structural facts about the venue session's model."""
        return self.inner.layout

    @property
    def tokenizer(self):
        """The venue session's tokenizer, or None."""
        return getattr(self.inner, "tokenizer", None)

    @property
    def in_process(self) -> bool:
        """True when the venue session serves a live in-process model, so `layout` facts such
        as `model_fingerprint` are weights-grade rather than config-grade. Venue-matched
        identity checks dispatch on this."""
        return hasattr(type(self.inner), "model")

    def _require_rollouts(self) -> None:
        if self._access < ModelAccess.ROLLOUTS:
            raise UnsupportedOperationError(
                f"{self._control_name} declared steer access '{self._access.name.lower()}', "
                "which does not include session generation; declare ModelAccess.ROLLOUTS or "
                "higher."
            )

    def generate(self, items, params):
        """Generate through the venue session; requires `ModelAccess.ROLLOUTS` or higher."""
        self._require_rollouts()
        return self.inner.generate(items, params)

    def score(self, items, params):
        """Score through the venue session; requires `ModelAccess.ROLLOUTS` or higher."""
        self._require_rollouts()
        return self.inner.score(items, params)

    def capture(self, prompts, layers, mode, location="layer_output"):
        """Capture through the venue session; requires `ModelAccess.CAPTURE` or higher."""
        if self._access < ModelAccess.CAPTURE:
            raise UnsupportedOperationError(
                f"{self._control_name} declared steer access '{self._access.name.lower()}', "
                "which does not include hidden-state capture; declare ModelAccess.CAPTURE or "
                "higher."
            )
        return self.inner.capture(prompts, layers, mode, location=location)
in_process property

True when the venue session serves a live in-process model, so layout facts such as model_fingerprint are weights-grade rather than config-grade. Venue-matched identity checks dispatch on this.

inner = inner instance-attribute
layout property

Structural facts about the venue session's model.

tokenizer property

The venue session's tokenizer, or None.

capture(prompts, layers, mode, location='layer_output')

Capture through the venue session; requires ModelAccess.CAPTURE or higher.

Source code in steerability/algorithms/core/execution/session_utils.py
170
171
172
173
174
175
176
177
178
def capture(self, prompts, layers, mode, location="layer_output"):
    """Capture through the venue session; requires `ModelAccess.CAPTURE` or higher."""
    if self._access < ModelAccess.CAPTURE:
        raise UnsupportedOperationError(
            f"{self._control_name} declared steer access '{self._access.name.lower()}', "
            "which does not include hidden-state capture; declare ModelAccess.CAPTURE or "
            "higher."
        )
    return self.inner.capture(prompts, layers, mode, location=location)
generate(items, params)

Generate through the venue session; requires ModelAccess.ROLLOUTS or higher.

Source code in steerability/algorithms/core/execution/session_utils.py
160
161
162
163
def generate(self, items, params):
    """Generate through the venue session; requires `ModelAccess.ROLLOUTS` or higher."""
    self._require_rollouts()
    return self.inner.generate(items, params)
score(items, params)

Score through the venue session; requires ModelAccess.ROLLOUTS or higher.

Source code in steerability/algorithms/core/execution/session_utils.py
165
166
167
168
def score(self, items, params):
    """Score through the venue session; requires `ModelAccess.ROLLOUTS` or higher."""
    self._require_rollouts()
    return self.inner.score(items, params)
SessionLM

A model-shaped adapter whose generation executes through a SteeringSession.

Gives steer-time helpers written against the model.generate calling convention (proposers, rollout scorers) an object with generate and device, so the helper runs on any backend. pad_token_id keyword arguments are dropped before submission, since sessions derive padding from their tokenizer.

Attributes:

Name Type Description
session

The wrapped session.

Source code in steerability/algorithms/core/execution/session_utils.py
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
class SessionLM:
    """A model-shaped adapter whose generation executes through a `SteeringSession`.

    Gives steer-time helpers written against the `model.generate` calling convention
    (proposers, rollout scorers) an object with `generate` and `device`, so the helper runs on
    any backend. `pad_token_id` keyword arguments are dropped before submission, since
    sessions derive padding from their tokenizer.

    Attributes:
        session: The wrapped session.
    """

    def __init__(self, session) -> None:
        self.session = session

    @property
    def device(self) -> torch.device:
        """CPU; sessions place prompt tensors themselves."""
        return torch.device("cpu")

    def generate(self, input_ids, attention_mask=None, **gen_kwargs) -> torch.Tensor:
        """Generate full sequences through the session (`model.generate` convention)."""
        gen_kwargs.pop("pad_token_id", None)
        return session_generate(self.session, input_ids, attention_mask, **gen_kwargs)
device property

CPU; sessions place prompt tensors themselves.

session = session instance-attribute
generate(input_ids, attention_mask=None, **gen_kwargs)

Generate full sequences through the session (model.generate convention).

Source code in steerability/algorithms/core/execution/session_utils.py
201
202
203
204
def generate(self, input_ids, attention_mask=None, **gen_kwargs) -> torch.Tensor:
    """Generate full sequences through the session (`model.generate` convention)."""
    gen_kwargs.pop("pad_token_id", None)
    return session_generate(self.session, input_ids, attention_mask, **gen_kwargs)
session_generate(session, input_ids, attention_mask=None, **gen_kwargs)

Run one generate call through a SteeringSession, returning full sequences.

Drop-in replacement for model.generate(input_ids=..., attention_mask=..., **gen_kwargs) inside driver rollouts and steer-time helpers. Each row of input_ids becomes one GenerationItem; the keyword arguments normalize through GenerationParams.from_gen_kwargs, so live logits_processor and stopping_criteria stacks travel in extra (consumable in process only). The returned tensor holds each caller row followed by its continuation per candidate, right-padded to a common length with the session tokenizer's pad token, so slicing at the input length recovers the continuations on every backend.

Parameters:

Name Type Description Default
session SteeringSession

The SteeringSession to generate on.

required
input_ids Tensor

Prompt token ids of shape [batch, seq_len].

required
attention_mask Tensor | None

Attention mask matching input_ids, or None.

None

Returns:

Type Description
Tensor

Full sequences of shape [batch * n, seq_len + gen_len].

Source code in steerability/algorithms/core/execution/session_utils.py
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
def session_generate(
    session: "SteeringSession",
    input_ids: torch.Tensor,
    attention_mask: torch.Tensor | None = None,
    **gen_kwargs,
) -> torch.Tensor:
    """Run one generate call through a `SteeringSession`, returning full sequences.

    Drop-in replacement for `model.generate(input_ids=..., attention_mask=..., **gen_kwargs)`
    inside driver rollouts and steer-time helpers. Each row of `input_ids` becomes one
    `GenerationItem`; the keyword arguments normalize through
    `GenerationParams.from_gen_kwargs`, so live `logits_processor` and `stopping_criteria`
    stacks travel in `extra` (consumable in process only). The returned tensor holds each
    caller row followed by its continuation per candidate, right-padded to a common length
    with the session tokenizer's pad token, so slicing at the input length recovers the
    continuations on every backend.

    Args:
        session: The `SteeringSession` to generate on.
        input_ids: Prompt token ids of shape `[batch, seq_len]`.
        attention_mask: Attention mask matching `input_ids`, or None.

    Returns:
        Full sequences of shape `[batch * n, seq_len + gen_len]`.
    """
    params = GenerationParams.from_gen_kwargs(**gen_kwargs)
    if input_ids.dim() == 1:
        input_ids = input_ids.unsqueeze(0)
    items = []
    for row in range(input_ids.size(0)):
        mask_row = attention_mask[row:row + 1] if attention_mask is not None else None
        items.append(GenerationItem(
            prompt=PreparedPrompt.from_token_ids(input_ids[row:row + 1], mask_row),
        ))
    results = session.generate(items, params)

    tokenizer = getattr(session, "tokenizer", None)
    pad_token_id = getattr(tokenizer, "pad_token_id", None)
    if pad_token_id is None:
        pad_token_id = getattr(tokenizer, "eos_token_id", None) or 0

    full_rows: list[torch.Tensor] = []
    for row, result in enumerate(results):
        prompt_ids = input_ids[row:row + 1]
        out_ids = result.output.output_ids.to(prompt_ids.device)
        repeated = prompt_ids.expand(out_ids.size(0), -1)
        full_rows.append(torch.cat([repeated, out_ids], dim=1))
    max_len = max(row.size(1) for row in full_rows)
    padded = [
        torch.nn.functional.pad(row, (0, max_len - row.size(1)), value=pad_token_id)
        for row in full_rows
    ]
    return torch.cat(padded, dim=0)
session_score(session, input_ids, ref_output_ids, attention_mask=None, **forward_kwargs)

Score reference tokens through a SteeringSession, teacher-forced.

Each row of input_ids becomes one ScoringItem; a single reference row broadcasts across the batch. Keyword arguments travel as forward keyword arguments.

Parameters:

Name Type Description Default
session SteeringSession

The SteeringSession to score on.

required
input_ids Tensor

Prompt token ids of shape [batch, seq_len] (a 1-D tensor is one row).

required
ref_output_ids Tensor

Reference tokens of shape [ref_len], [1, ref_len], or [batch, ref_len].

required
attention_mask Tensor | None

Attention mask matching input_ids, or None.

None

Returns:

Type Description
Tensor

Log probabilities of shape [batch, ref_len].

Source code in steerability/algorithms/core/execution/session_utils.py
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
def session_score(
    session: "SteeringSession",
    input_ids: torch.Tensor,
    ref_output_ids: torch.Tensor,
    attention_mask: torch.Tensor | None = None,
    **forward_kwargs,
) -> torch.Tensor:
    """Score reference tokens through a `SteeringSession`, teacher-forced.

    Each row of `input_ids` becomes one `ScoringItem`; a single reference row broadcasts
    across the batch. Keyword arguments travel as forward keyword arguments.

    Args:
        session: The `SteeringSession` to score on.
        input_ids: Prompt token ids of shape `[batch, seq_len]` (a 1-D tensor is one row).
        ref_output_ids: Reference tokens of shape `[ref_len]`, `[1, ref_len]`, or
            `[batch, ref_len]`.
        attention_mask: Attention mask matching `input_ids`, or None.

    Returns:
        Log probabilities of shape `[batch, ref_len]`.
    """
    params = GenerationParams(extra=forward_kwargs)
    if input_ids.dim() == 1:
        input_ids = input_ids.unsqueeze(0)
    if ref_output_ids.dim() == 1:
        ref_output_ids = ref_output_ids.unsqueeze(0)
    if ref_output_ids.size(0) == 1 and input_ids.size(0) > 1:
        ref_output_ids = ref_output_ids.expand(input_ids.size(0), -1)
    items = []
    for row in range(input_ids.size(0)):
        mask_row = attention_mask[row:row + 1] if attention_mask is not None else None
        items.append(ScoringItem(
            prompt=PreparedPrompt.from_token_ids(input_ids[row:row + 1], mask_row),
            ref_output_ids=ref_output_ids[row:row + 1],
        ))
    return session.score(items, params)

spec

Frozen backend identity, expressed as BackendSpec with canonicalized options.

KNOWN_BACKEND_KINDS = ('huggingface', 'vllm', 'vllm-serve') module-attribute
BackendSpec dataclass

Frozen, hashable identity of one backend configuration.

The spec hash is the backend identity used for engine caching, benchmark checkpoint keys, capability-probe caches, and artifact provenance. Options are canonicalized at construction (nested mappings stored as sorted tuples, dtypes as strings, no live objects), so two specs built from equal option mappings compare and hash equal regardless of key order. Equality and hash() follow spec_hash, so value type is part of identity (an option value of True and one of 1 yield different specs).

Construction also validates the configuration. A "vllm"/"vllm-serve" spec with the vLLM-Hook plugin active (hook_plugin option) and speculative decoding configured (speculative_config option, top-level or under engine_kwargs) is rejected, since draft-model forwards are unhooked and verification passes break the worker's per-request position accounting. A "vllm"/"vllm-serve" spec naming an encoder-decoder model is rejected when the model config resolves locally (encoder-decoder execution is in-process only); an unresolvable reference passes here and is re-checked at backend construction.

Attributes:

Name Type Description
kind str

Backend kind, one of "huggingface", "vllm", or "vllm-serve".

model str | None

Model reference (hub id or local path), or None when the backend adopts an already-loaded model.

options Any

Canonicalized option mapping, stored as sorted tuples.

Raises:

Type Description
ValueError

If kind is unknown, a vLLM spec combines the vLLM-Hook plugin with speculative decoding, or a vLLM spec names a locally resolvable encoder-decoder model.

TypeError

If options is neither a mapping nor a canonical options tuple.

Source code in steerability/algorithms/core/execution/spec.py
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
@dataclass(frozen=True, slots=True, eq=False)
class BackendSpec:
    """Frozen, hashable identity of one backend configuration.

    The spec hash is the backend identity used for engine caching, benchmark checkpoint keys,
    capability-probe caches, and artifact provenance. Options are canonicalized at construction
    (nested mappings stored as sorted tuples, dtypes as strings, no live objects), so two specs
    built from equal option mappings compare and hash equal regardless of key order. Equality
    and `hash()` follow `spec_hash`, so value type is part of identity (an option value of
    `True` and one of `1` yield different specs).

    Construction also validates the configuration. A `"vllm"`/`"vllm-serve"` spec with the
    vLLM-Hook plugin active (`hook_plugin` option) and speculative decoding configured
    (`speculative_config` option, top-level or under `engine_kwargs`) is rejected, since
    draft-model forwards are unhooked and verification passes break the worker's per-request
    position accounting. A `"vllm"`/`"vllm-serve"` spec naming an encoder-decoder model is
    rejected when the model config resolves locally (encoder-decoder execution is in-process
    only); an unresolvable reference passes here and is re-checked at backend construction.

    Attributes:
        kind: Backend kind, one of `"huggingface"`, `"vllm"`, or `"vllm-serve"`.
        model: Model reference (hub id or local path), or None when the backend adopts an
            already-loaded model.
        options: Canonicalized option mapping, stored as sorted tuples.

    Raises:
        ValueError: If `kind` is unknown, a vLLM spec combines the vLLM-Hook plugin with
            speculative decoding, or a vLLM spec names a locally resolvable encoder-decoder
            model.
        TypeError: If `options` is neither a mapping nor a canonical options tuple.
    """

    kind: str
    model: str | None = None
    options: Any = field(default=())

    def __post_init__(self) -> None:
        if self.kind not in KNOWN_BACKEND_KINDS:
            raise ValueError(
                f"Unknown backend kind {self.kind!r}; known kinds are {', '.join(KNOWN_BACKEND_KINDS)}."
            )
        if isinstance(self.model, Path):
            object.__setattr__(self, "model", str(self.model))
        raw_options = self.options
        if isinstance(raw_options, Mapping):
            object.__setattr__(self, "options", canonicalize_option_value(raw_options))
        elif raw_options == ():
            object.__setattr__(self, "options", canonicalize_option_value({}))
        elif not (isinstance(raw_options, tuple) and len(raw_options) == 2 and raw_options[0] == _MAPPING_TAG):
            raise TypeError(
                f"options must be a mapping or a canonical options tuple; got "
                f"{type(raw_options).__name__}."
            )

        if self.kind in ("vllm", "vllm-serve"):
            if self.get_option("hook_plugin"):
                speculative = (
                    self.get_option("speculative_config")
                    or self.get_option("engine_kwargs", "speculative_config")
                )
                if speculative:
                    raise ValueError(
                        "Speculative decoding cannot be combined with the vLLM-Hook plugin: "
                        "draft-model forwards are unhooked and verification passes break the "
                        "worker's per-request position accounting."
                    )
                if (
                    self.kind == "vllm"
                    and self.get_option("engine_kwargs", "enforce_eager") is False
                ):
                    raise ValueError(
                        "enforce_eager=False cannot be combined with the vLLM-Hook plugin: "
                        "worker hooks do not run under CUDA-graph replay. Drop the option "
                        "(hook_plugin engines default to eager execution) or disable the plugin."
                    )
            if self.model is not None:
                _reject_encoder_decoder_if_resolvable(
                    self.model, bool(self.get_option("trust_remote_code", default=False)),
                )

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, BackendSpec):
            return NotImplemented
        return self._identity() == other._identity()

    def __hash__(self) -> int:
        return hash(self._identity())

    def _identity(self) -> tuple[str, str | None, str]:
        return (self.kind, self.model, repr(self.options))

    def get_option(self, *path: str, default: Any = None) -> Any:
        """Read one option by key path, rebuilding plain dicts and lists on the way out.

        Args:
            *path: Nested option keys, e.g. `get_option("hf_model_kwargs", "attn_implementation")`.
            default: Value returned when any key along the path is absent.

        Returns:
            The option value with mappings rebuilt as plain dicts and sequences as plain lists,
            or `default`.
        """
        value: Any = self.options
        for key in path:
            if not (isinstance(value, tuple) and len(value) == 2 and value[0] == _MAPPING_TAG):
                return default
            entries = dict(value[1])
            if key not in entries:
                return default
            value = entries[key]
        return _decanonicalize(value)

    def options_dict(self) -> dict[str, Any]:
        """Return the options as a plain nested dict (empty when no options were provided)."""
        rebuilt = _decanonicalize(self.options)
        return rebuilt if isinstance(rebuilt, dict) else {}

    @property
    def spec_hash(self) -> str:
        """A 16-character hex digest over `(kind, model, options)`, consistent with `__eq__`
        and stable across processes for plain-data options."""
        digest = hashlib.sha256(repr(self._identity()).encode("utf-8"))
        return digest.hexdigest()[:16]
kind instance-attribute
model = None class-attribute instance-attribute
options = field(default=()) class-attribute instance-attribute
spec_hash property

A 16-character hex digest over (kind, model, options), consistent with __eq__ and stable across processes for plain-data options.

get_option(*path, default=None)

Read one option by key path, rebuilding plain dicts and lists on the way out.

Parameters:

Name Type Description Default
*path str

Nested option keys, e.g. get_option("hf_model_kwargs", "attn_implementation").

()
default Any

Value returned when any key along the path is absent.

None

Returns:

Type Description
Any

The option value with mappings rebuilt as plain dicts and sequences as plain lists,

Any

or default.

Source code in steerability/algorithms/core/execution/spec.py
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
def get_option(self, *path: str, default: Any = None) -> Any:
    """Read one option by key path, rebuilding plain dicts and lists on the way out.

    Args:
        *path: Nested option keys, e.g. `get_option("hf_model_kwargs", "attn_implementation")`.
        default: Value returned when any key along the path is absent.

    Returns:
        The option value with mappings rebuilt as plain dicts and sequences as plain lists,
        or `default`.
    """
    value: Any = self.options
    for key in path:
        if not (isinstance(value, tuple) and len(value) == 2 and value[0] == _MAPPING_TAG):
            return default
        entries = dict(value[1])
        if key not in entries:
            return default
        value = entries[key]
    return _decanonicalize(value)
options_dict()

Return the options as a plain nested dict (empty when no options were provided).

Source code in steerability/algorithms/core/execution/spec.py
211
212
213
214
def options_dict(self) -> dict[str, Any]:
    """Return the options as a plain nested dict (empty when no options were provided)."""
    rebuilt = _decanonicalize(self.options)
    return rebuilt if isinstance(rebuilt, dict) else {}
canonicalize_option_value(value)

Convert one option value to a hashable canonical form.

Mappings become ("__mapping__", ((key, value), ...)) tuples ordered by key type name and key repr, with scalar keys (str, int, bool, float) preserved as-is; sequences become ("__sequence__", (value, ...)) tuples; torch.dtype, torch.device, and pathlib.Path values become strings (dtypes without the torch. prefix); scalars pass through. Any other object is rendered as "<qualname>:<repr>", which keeps spec construction total but makes the value only as stable as the object's repr; options should be plain data.

Parameters:

Name Type Description Default
value Any

The option value to canonicalize.

required

Returns:

Type Description
Any

A hashable canonical form of value.

Source code in steerability/algorithms/core/execution/spec.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def canonicalize_option_value(value: Any) -> Any:
    """Convert one option value to a hashable canonical form.

    Mappings become `("__mapping__", ((key, value), ...))` tuples ordered by key type name and
    key repr, with scalar keys (str, int, bool, float) preserved as-is; sequences become
    `("__sequence__", (value, ...))` tuples; `torch.dtype`, `torch.device`, and `pathlib.Path`
    values become strings (dtypes without the `torch.` prefix); scalars pass through. Any other
    object is rendered as `"<qualname>:<repr>"`, which keeps spec construction total but makes
    the value only as stable as the object's `repr`; options should be plain data.

    Args:
        value: The option value to canonicalize.

    Returns:
        A hashable canonical form of `value`.
    """
    if isinstance(value, Mapping):
        entries = []
        for key, val in value.items():
            canonical_key = key if isinstance(key, (str, int, bool, float)) else str(key)
            entries.append((canonical_key, canonicalize_option_value(val)))
        entries.sort(key=lambda entry: (type(entry[0]).__qualname__, repr(entry[0])))
        return (_MAPPING_TAG, tuple(entries))
    if isinstance(value, (list, tuple)):
        return (_SEQUENCE_TAG, tuple(canonicalize_option_value(item) for item in value))
    if isinstance(value, torch.dtype):
        return str(value).removeprefix("torch.")
    if isinstance(value, torch.device):
        return str(value)
    if isinstance(value, Path):
        return str(value)
    if value is None or isinstance(value, (str, int, float, bool)):
        return value
    return f"{type(value).__qualname__}:{value!r}"

staging

Stage mechanics for the engine-backed steer phase: the stage free protocol and the steer-time capture smoke test.

The free protocol takes only a weakref.ref; a strong reference crossing the function boundary would keep the staged model alive through gc.collect() and defeat the check.

capture_smoke_failure(session, fallback_tokenizer=None)

Issue one single-prompt capture through session; the error text on failure.

The probe token id comes from the session's tokenizer, else fallback_tokenizer.

Source code in steerability/algorithms/core/execution/staging.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def capture_smoke_failure(session, fallback_tokenizer=None) -> str | None:
    """Issue one single-prompt capture through `session`; the error text on failure.

    The probe token id comes from the session's tokenizer, else `fallback_tokenizer`.
    """
    tokenizer = getattr(session, "tokenizer", None) or fallback_tokenizer
    token_id = 0
    for attribute in ("bos_token_id", "eos_token_id", "pad_token_id"):
        value = getattr(tokenizer, attribute, None)
        if value is not None:
            token_id = int(value)
            break
    prompt = PreparedPrompt.from_token_ids(torch.tensor([[token_id]], dtype=torch.long))
    try:
        session.capture([prompt], layers=[0], mode="last_token", location="layer_output")
    except Exception as error:
        return str(error)
    return None
find_model_holders(referent, controls)

Controls holding referent in their instance attributes (one level) or in a bound intervention's transform or gate attributes.

Source code in steerability/algorithms/core/execution/staging.py
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
def find_model_holders(referent, controls) -> list[str]:
    """Controls holding `referent` in their instance attributes (one level) or in a bound
    intervention's transform or gate attributes."""

    def instance_values(obj):
        try:
            return list(vars(obj).values())
        except TypeError:
            slots = getattr(type(obj), "__slots__", ())
            return [getattr(obj, name, None) for name in slots]

    holders: list[str] = []
    for control in controls:
        found = any(value is referent for value in instance_values(control))
        if not found:
            for intervention in getattr(control, "interventions", ()) or ():
                for slot in (
                    getattr(intervention, "transform", None),
                    getattr(intervention, "gate", None),
                ):
                    if slot is not None and any(
                        value is referent for value in instance_values(slot)
                    ):
                        found = True
        if found:
            holders.append(type(control).__name__)
    return holders
verify_stage_released(ref, controls)

Verify the staged in-process model's weights are actually gone.

Runs a collection pass, clears the CUDA cache, and dereferences ref (the caller must have dropped its own strong reference first).

Raises:

Type Description
RuntimeError

If a control retained the staged model past the stage; the message names the retaining controls where identifiable.

Source code in steerability/algorithms/core/execution/staging.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def verify_stage_released(ref: weakref.ref, controls) -> None:
    """Verify the staged in-process model's weights are actually gone.

    Runs a collection pass, clears the CUDA cache, and dereferences `ref` (the caller must
    have dropped its own strong reference first).

    Raises:
        RuntimeError: If a control retained the staged model past the stage; the message
            names the retaining controls where identifiable.
    """
    gc.collect()
    if torch.cuda.is_available():
        torch.cuda.empty_cache()
    referent = ref()
    if referent is None:
        return
    holders = find_model_holders(referent, controls)
    names = ", ".join(holders) if holders else "an unidentified holder"
    raise RuntimeError(
        f"The staged in-process model was retained past the steer stage by: {names}. "
        "Controls supported at generate on this backend must not hold the pipeline model "
        "beyond steer(); release every instance reference to it before steer() returns, or "
        "require Capability.IN_PROCESS_TORCH at generate."
    )

identity

Canonical configuration identity and trial-seed derivation for configuration sweeps.

Pure functions with no I/O. Config identity is a digest over the materialized pipeline (control classes and their full constructor parameters), stable across processes and machines for every handled value type. The module does not import ControlSpec; spec objects are duck-typed on their control_cls and name attributes.

logger = logging.getLogger(__name__) module-attribute

canonical_value(obj, _path='$')

JSON-serializable canonical form of a constructor-argument value.

The form is stable across processes and machines for every handled type. Tensor identity is content-addressed over dtype, shape, and bytes, with device and requires_grad excluded. Mapping key order never affects the form, sequence order always does, and set element order never does. A callable reduces to its qualified name. An unhandled object type reduces to its type qualname (value-blind), logged at debug. NumPy scalars reduce with item(); NumPy arrays convert through tolist() and then recurse, so the elements of object arrays follow the same rules as list elements.

Parameters:

Name Type Description Default
obj Any

The value to canonicalize.

required
_path str

Internal breadcrumb naming the position of obj within the enclosing structure, used only in the debug log for value-blind fallbacks.

'$'

Returns:

Type Description
Any

A JSON-serializable canonical representation of obj.

Source code in steerability/algorithms/core/identity.py
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
def canonical_value(obj: Any, _path: str = "$") -> Any:
    """JSON-serializable canonical form of a constructor-argument value.

    The form is stable across processes and machines for every handled type. Tensor identity is
    content-addressed over dtype, shape, and bytes, with device and `requires_grad` excluded.
    Mapping key order never affects the form, sequence order always does, and set element order
    never does. A callable reduces to its qualified name. An unhandled object type reduces to its
    type qualname (value-blind), logged at debug. NumPy scalars reduce with `item()`; NumPy arrays
    convert through `tolist()` and then recurse, so the elements of object arrays follow the same
    rules as list elements.

    Args:
        obj: The value to canonicalize.
        _path: Internal breadcrumb naming the position of `obj` within the enclosing structure,
            used only in the debug log for value-blind fallbacks.

    Returns:
        A JSON-serializable canonical representation of `obj`.
    """
    if obj is None or isinstance(obj, (str, int, float, bool)):
        return obj
    if isinstance(obj, Path):
        return str(obj)
    if isinstance(obj, np.generic):
        return obj.item()
    if isinstance(obj, np.ndarray):
        return canonical_value(obj.tolist(), _path)
    if isinstance(obj, torch.Tensor):
        tensor = obj.detach().to("cpu").contiguous()
        digest = hashlib.sha256()
        digest.update(str(tensor.dtype).encode())
        digest.update(str(tuple(tensor.shape)).encode())
        digest.update(_tensor_payload(tensor))
        return {
            _TENSOR_TAG: {
                "sha256": digest.hexdigest(),
                "shape": list(tensor.shape),
                "dtype": str(tensor.dtype),
            }
        }
    if dataclasses.is_dataclass(obj) and not isinstance(obj, type):
        return {
            _DATACLASS_TAG: qualname(type(obj)),
            "fields": {
                field.name: canonical_value(getattr(obj, field.name), f"{_path}.{field.name}")
                for field in dataclasses.fields(obj)
            },
        }
    if isinstance(obj, Mapping):
        items = sorted(obj.items(), key=lambda kv: str(kv[0]))
        return {str(key): canonical_value(value, f"{_path}[{key!r}]") for key, value in items}
    if isinstance(obj, (set, frozenset)):
        canonical = [canonical_value(item, _path) for item in obj]
        return sorted(canonical, key=lambda value: json.dumps(value, sort_keys=True))
    if isinstance(obj, (list, tuple)):
        return [canonical_value(item, f"{_path}[{i}]") for i, item in enumerate(obj)]
    if callable(obj):
        return f"callable:{getattr(obj, '__qualname__', type(obj).__name__)}"
    logger.debug("canonical_value: value-blind fallback for %s at %s", qualname(type(obj)), _path)
    return {_TYPE_TAG: qualname(type(obj))}

config_descriptor_from_controls(controls)

Descriptor for a fixed-control configuration, recovered from each control's args.

Construction stores the validated Args dataclass as control.args; arg-free controls (Args = None) have no such attribute and contribute empty params. This distinguishes two fixed pipelines that differ only in their controls' configuration.

Parameters:

Name Type Description Default
controls Sequence[Any]

Instantiated controls, in list order.

required

Returns:

Type Description
dict

A descriptor dict with a "controls" list, one entry per control.

Source code in steerability/algorithms/core/identity.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
def config_descriptor_from_controls(controls: Sequence[Any]) -> dict:
    """Descriptor for a fixed-control configuration, recovered from each control's `args`.

    Construction stores the validated `Args` dataclass as `control.args`; arg-free controls
    (`Args = None`) have no such attribute and contribute empty params. This distinguishes two
    fixed pipelines that differ only in their controls' configuration.

    Args:
        controls: Instantiated controls, in list order.

    Returns:
        A descriptor dict with a `"controls"` list, one entry per control.
    """
    entries = []
    for control in controls:
        args = getattr(control, "args", None)
        entries.append({
            "control": qualname(type(control)),
            "params": canonical_value(args) if args is not None else {},
            "enabled": bool(getattr(control, "enabled", True)),
        })
    return {"controls": entries}

config_descriptor_from_specs(specs, params)

Descriptor for a spec-defined configuration, from the resolved per-spec kwargs.

Each spec contributes one control entry keyed by its resolved name (its name, or its control_cls.__name__), carrying the canonical form of the resolved constructor kwargs. Entry order follows specs, so sequence order participates in identity.

Parameters:

Name Type Description Default
specs Sequence[Any]

The specs of one configuration, in list order; each duck-typed on control_cls and name.

required
params Mapping[str, Mapping[str, Any]]

Mapping from resolved spec name to that spec's resolved constructor kwargs.

required

Returns:

Type Description
dict

A descriptor dict with a "controls" list, one entry per spec.

Source code in steerability/algorithms/core/identity.py
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def config_descriptor_from_specs(specs: Sequence[Any], params: Mapping[str, Mapping[str, Any]]) -> dict:
    """Descriptor for a spec-defined configuration, from the resolved per-spec kwargs.

    Each spec contributes one control entry keyed by its resolved name (its `name`, or its
    `control_cls.__name__`), carrying the canonical form of the resolved constructor kwargs. Entry
    order follows `specs`, so sequence order participates in identity.

    Args:
        specs: The specs of one configuration, in list order; each duck-typed on `control_cls`
            and `name`.
        params: Mapping from resolved spec name to that spec's resolved constructor kwargs.

    Returns:
        A descriptor dict with a `"controls"` list, one entry per spec.
    """
    return {
        "controls": [
            {
                "control": qualname(spec.control_cls),
                "params": canonical_value(dict(params[spec.name or spec.control_cls.__name__])),
                "enabled": True,
            }
            for spec in specs
        ]
    }

config_digest(descriptor)

A 12-hex-character sha256 of the descriptor's sorted JSON form.

A pure function of descriptor: equal descriptors always digest equal.

Parameters:

Name Type Description Default
descriptor Mapping[str, Any]

A JSON-serializable descriptor, e.g. from config_descriptor_from_controls.

required

Returns:

Type Description
str

The 12-character hex digest.

Source code in steerability/algorithms/core/identity.py
172
173
174
175
176
177
178
179
180
181
182
183
184
def config_digest(descriptor: Mapping[str, Any]) -> str:
    """A 12-hex-character sha256 of the descriptor's sorted JSON form.

    A pure function of `descriptor`: equal descriptors always digest equal.

    Args:
        descriptor: A JSON-serializable descriptor, e.g. from `config_descriptor_from_controls`.

    Returns:
        The 12-character hex digest.
    """
    serialized = json.dumps(descriptor, sort_keys=True)
    return hashlib.sha256(serialized.encode()).hexdigest()[:12]

derive_trial_seed(base_seed, config_id, trial_id)

Deterministic per-(config, trial) seed derived from a benchmark-level base seed.

A pure function of its three inputs, distinct across trial_id values and across config_id values by construction.

Parameters:

Name Type Description Default
base_seed int

The benchmark-level base seed.

required
config_id str

The configuration identifier.

required
trial_id int

The trial index.

required

Returns:

Type Description
int

A 32-bit non-negative integer seed.

Source code in steerability/algorithms/core/identity.py
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
def derive_trial_seed(base_seed: int, config_id: str, trial_id: int) -> int:
    """Deterministic per-(config, trial) seed derived from a benchmark-level base seed.

    A pure function of its three inputs, distinct across `trial_id` values and across `config_id`
    values by construction.

    Args:
        base_seed: The benchmark-level base seed.
        config_id: The configuration identifier.
        trial_id: The trial index.

    Returns:
        A 32-bit non-negative integer seed.
    """
    digest = hashlib.sha256(f"{base_seed}:{config_id}:{trial_id}".encode()).digest()
    return int.from_bytes(digest[:4], "big")

qualname(obj_type)

Fully qualified name of a type, as <module>.<qualname>.

Parameters:

Name Type Description Default
obj_type type

The type to name.

required

Returns:

Type Description
str

The dotted module-plus-qualname string.

Source code in steerability/algorithms/core/identity.py
26
27
28
29
30
31
32
33
34
35
def qualname(obj_type: type) -> str:
    """Fully qualified name of a type, as `<module>.<qualname>`.

    Args:
        obj_type: The type to name.

    Returns:
        The dotted module-plus-qualname string.
    """
    return f"{obj_type.__module__}.{obj_type.__qualname__}"

output

The Output generation record, per-row finish-reason inference, and the stop-string truncation rule shared by every backend.

FINISH_REASONS = ('stop', 'eos', 'length') module-attribute

Output dataclass

The result of one generation call.

Attributes:

Name Type Description
output_ids Tensor

Generated token IDs as a [batch, seq] tensor, excluding the prompt (the same slice the pipeline returns to the caller by default). Token ids are returned as generated; stop strings and any token-boundary overrun are not removed from them.

adapted_input_ids Tensor | None

The input_ids actually fed to the model after all input-control transformations. For a padded batch these are in left-packed layout. None if not provided by the producer.

finish_reason str | None

The first row's finish reason, one of "stop", "eos", "length", or None when none can be inferred.

finish_reasons tuple[str | None, ...] | None

Per-row finish reasons matching output_ids (one entry per candidate when the producer generated several), or None when the producer reports only the first row's reason.

generated_tokens int | None

The total tokens generated to produce this output, including rollouts a decoding driver proposed and discarded, or None when the producer did not count them. On the driver path the pipeline attaches the session wrapper's accumulated total; for a multi-row dispatch the total is split evenly across rows (integer division, remainder on the first row), so arm-level sums are preserved. The driverless path leaves it None, and consumers fall back to the non-pad count of output_ids.

Source code in steerability/algorithms/core/output.py
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@dataclass(slots=True)
class Output:
    """The result of one generation call.

    Attributes:
        output_ids: Generated token IDs as a `[batch, seq]` tensor, excluding the prompt (the same
            slice the pipeline returns to the caller by default). Token ids are returned as
            generated; stop strings and any token-boundary overrun are not removed from them.
        adapted_input_ids: The `input_ids` actually fed to the model after all input-control
            transformations. For a padded batch these are in left-packed layout. None if not
            provided by the producer.
        finish_reason: The first row's finish reason, one of `"stop"`, `"eos"`, `"length"`, or
            None when none can be inferred.
        finish_reasons: Per-row finish reasons matching `output_ids` (one entry per candidate
            when the producer generated several), or None when the producer reports only the
            first row's reason.
        generated_tokens: The total tokens generated to produce this output, including rollouts a
            decoding driver proposed and discarded, or None when the producer did not count them.
            On the driver path the pipeline attaches the session wrapper's accumulated total; for a
            multi-row dispatch the total is split evenly across rows (integer division, remainder
            on the first row), so arm-level sums are preserved. The driverless path leaves it None,
            and consumers fall back to the non-pad count of `output_ids`.
    """
    output_ids: torch.Tensor
    adapted_input_ids: torch.Tensor | None = None
    finish_reason: str | None = None
    finish_reasons: tuple[str | None, ...] | None = None
    generated_tokens: int | None = None

    def decode(
        self,
        tokenizer: "PreTrainedTokenizerBase",
        skip_special_tokens: bool = True,
    ) -> list[str]:
        """Decode `output_ids` to text. Batch-aware."""
        return tokenizer.decode(
            self.output_ids, skip_special_tokens=skip_special_tokens
        )
adapted_input_ids = None class-attribute instance-attribute
finish_reason = None class-attribute instance-attribute
finish_reasons = None class-attribute instance-attribute
generated_tokens = None class-attribute instance-attribute
output_ids instance-attribute
decode(tokenizer, skip_special_tokens=True)

Decode output_ids to text. Batch-aware.

Source code in steerability/algorithms/core/output.py
43
44
45
46
47
48
49
50
51
def decode(
    self,
    tokenizer: "PreTrainedTokenizerBase",
    skip_special_tokens: bool = True,
) -> list[str]:
    """Decode `output_ids` to text. Batch-aware."""
    return tokenizer.decode(
        self.output_ids, skip_special_tokens=skip_special_tokens
    )

infer_finish_reasons(new_tokens, gen_kwargs, *, eos_token_id, pad_token_id, stop_strings=(), stop_token_ids=(), tokenizer=None)

Classify a per-row finish reason from generated token IDs and the composed stop rules.

Parameters:

Name Type Description Default
new_tokens Tensor

Generated token IDs as a [batch, gen_len] tensor, right-padded by generate (the continuation only, with the prompt excluded).

required
gen_kwargs dict

Generation parameters; only max_new_tokens is consulted.

required
eos_token_id int | list[int] | None

End-of-sequence token ID(s); an int, a list of ints, or None. Normalized to a set of IDs internally.

required
pad_token_id int | None

Padding token ID used to right-pad short rows, or None.

required
stop_strings Sequence[str]

Stop strings composed for this generation; requires tokenizer to take effect.

()
stop_token_ids Sequence[int]

Extra stop token ids composed for this generation.

()
tokenizer PreTrainedTokenizerBase | None

Tokenizer used to decode continuations for the stop-string test, or None.

None

Returns:

Type Description
list[str | None]

One reason per row, in order, classified with the precedence stop, then eos, then

list[str | None]

length, then None. For row i, trailing pad_token_id positions are stripped to

list[str | None]

recover the true continuation length n, then:

  • "stop" if the decoded continuation contains a stop string (when a tokenizer is available), or the last unstripped token is one of stop_token_ids;
  • "eos" if n > 0 and the last unstripped token is in the eos set, or pad_token_id is in the eos set and at least one trailing token was stripped (the pad-equals-eos configuration common to Llama-family tokenizers, where the first stripped token was the genuine EOS);
  • "length" if max_new_tokens is set and n >= max_new_tokens;
  • None otherwise (including zero-length rows).

Stop rules the classifier was not given, such as caller-supplied custom stopping criteria, still classify as None.

Source code in steerability/algorithms/core/output.py
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
def infer_finish_reasons(
    new_tokens: torch.Tensor,
    gen_kwargs: dict,
    *,
    eos_token_id: int | list[int] | None,
    pad_token_id: int | None,
    stop_strings: Sequence[str] = (),
    stop_token_ids: Sequence[int] = (),
    tokenizer: PreTrainedTokenizerBase | None = None,
) -> list[str | None]:
    """Classify a per-row finish reason from generated token IDs and the composed stop rules.

    Args:
        new_tokens: Generated token IDs as a `[batch, gen_len]` tensor, right-padded by `generate`
            (the continuation only, with the prompt excluded).
        gen_kwargs: Generation parameters; only `max_new_tokens` is consulted.
        eos_token_id: End-of-sequence token ID(s); an int, a list of ints, or None. Normalized to a
            set of IDs internally.
        pad_token_id: Padding token ID used to right-pad short rows, or None.
        stop_strings: Stop strings composed for this generation; requires `tokenizer` to take
            effect.
        stop_token_ids: Extra stop token ids composed for this generation.
        tokenizer: Tokenizer used to decode continuations for the stop-string test, or None.

    Returns:
        One reason per row, in order, classified with the precedence stop, then eos, then
        length, then None. For row `i`, trailing `pad_token_id` positions are stripped to
        recover the true continuation length `n`, then:

            - `"stop"` if the decoded continuation contains a stop string (when a tokenizer is
              available), or the last unstripped token is one of `stop_token_ids`;
            - `"eos"` if `n > 0` and the last unstripped token is in the eos set, or
              `pad_token_id` is in the eos set and at least one trailing token was stripped (the
              pad-equals-eos configuration common to Llama-family tokenizers, where the first
              stripped token was the genuine EOS);
            - `"length"` if `max_new_tokens` is set and `n >= max_new_tokens`;
            - None otherwise (including zero-length rows).

    Stop rules the classifier was not given, such as caller-supplied custom stopping criteria,
    still classify as None.
    """
    eos_ids: set[int] = set()
    if isinstance(eos_token_id, int):
        eos_ids = {eos_token_id}
    elif eos_token_id is not None:
        eos_ids = {int(token_id) for token_id in eos_token_id}

    stop_ids = {int(token_id) for token_id in stop_token_ids}
    stop_texts = [text for text in stop_strings if text]
    max_new = gen_kwargs.get("max_new_tokens")
    pad_equals_eos = pad_token_id is not None and pad_token_id in eos_ids

    reasons: list[str | None] = []
    for row in new_tokens:
        row_list = row.tolist()

        stripped_any = False
        if pad_token_id is not None:
            end = len(row_list)
            while end > 0 and row_list[end - 1] == pad_token_id:
                end -= 1
            stripped_any = end < len(row_list)
            row_list = row_list[:end]

        n = len(row_list)

        stopped = n > 0 and row_list[-1] in stop_ids
        if not stopped and stop_texts and tokenizer is not None and n > 0:
            continuation = tokenizer.decode(row_list, skip_special_tokens=False)
            stopped = any(text in continuation for text in stop_texts)

        if stopped:
            reasons.append("stop")
        elif n > 0 and row_list[-1] in eos_ids:
            reasons.append("eos")
        elif pad_equals_eos and stripped_any:
            reasons.append("eos")
        elif max_new is not None and n >= max_new:
            reasons.append("length")
        else:
            reasons.append(None)

    return reasons

truncate_at_stop_strings(text, stop_strings)

Truncate text at the earliest occurrence of any stop string.

This is the one client-side truncation rule applied to decoded continuation text on every backend. Token ids are never modified; only the decoded text is cut, at the start of the earliest match.

With reasoning models the earliest-match rule interacts with thinking segments: a stop string that also occurs inside the reasoning (e.g. "Answer:") cuts the text mid-thinking, so the thinking segment is left unclosed and a later split reports an empty answer. Choose stop strings that cannot appear before the closing think tag, or omit them when generating with thinking on.

Parameters:

Name Type Description Default
text str

Decoded continuation text.

required
stop_strings Sequence[str]

Stop strings; empty leaves text unchanged.

required

Returns:

Type Description
str

text up to (excluding) the earliest stop-string occurrence, or text unchanged when

str

no stop string occurs.

Source code in steerability/algorithms/core/output.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
def truncate_at_stop_strings(text: str, stop_strings: Sequence[str]) -> str:
    """Truncate `text` at the earliest occurrence of any stop string.

    This is the one client-side truncation rule applied to decoded continuation text on every
    backend. Token ids are never modified; only the decoded text is cut, at the start of the
    earliest match.

    With reasoning models the earliest-match rule interacts with thinking segments: a stop string
    that also occurs inside the reasoning (e.g. `"Answer:"`) cuts the text mid-thinking, so the
    thinking segment is left unclosed and a later split reports an empty answer. Choose stop strings
    that cannot appear before the closing think tag, or omit them when generating with thinking on.

    Args:
        text: Decoded continuation text.
        stop_strings: Stop strings; empty leaves `text` unchanged.

    Returns:
        `text` up to (excluding) the earliest stop-string occurrence, or `text` unchanged when
        no stop string occurs.
    """
    cut = len(text)
    for stop in stop_strings:
        if not stop:
            continue
        index = text.find(stop)
        if index != -1 and index < cut:
            cut = index
    return text[:cut]

scoring

The per-row scorer protocol consumed by steering controls.

SampleScorer

Bases: Protocol

Score one response against its row; higher is better.

The row is a mapping carrying "input" (the query text), "reference" when the dataset has one, and any other dataset columns. Controls that optimize or rerank against a per-row score (prompt optimizers, sequence rerankers) accept any callable with this shape.

Source code in steerability/algorithms/core/scoring.py
 5
 6
 7
 8
 9
10
11
12
13
14
@runtime_checkable
class SampleScorer(Protocol):
    """Score one response against its row; higher is better.

    The row is a mapping carrying `"input"` (the query text), `"reference"` when the dataset has
    one, and any other dataset columns. Controls that optimize or rerank against a per-row score
    (prompt optimizers, sequence rerankers) accept any callable with this shape.
    """

    def __call__(self, response: str, row: Mapping[str, Any]) -> float: ...

specs

Specification utilities for steering controls.

Provides:

  • ControlSpec: a description of a steering control plus a hyperparameter search space.

Space = Mapping[str, Sequence[Any]] | Sequence[Mapping[str, Any]] | Callable[[dict], Iterable[Mapping[str, Any]]] module-attribute

ControlSpec dataclass

Specification for a parameterized steering control.

A ControlSpec describes a control class plus a search space over its constructor arguments. The sweep layer (core/sweeps.py, and SteeringEval above it) uses it to instantiate control instances for different hyperparameter settings.

Attributes:

Name Type Description
control_cls type

The steering control class to instantiate.

params Mapping[str, Any]

Fixed constructor arguments for the control.

vars Space | None

Optional search space over additional constructor arguments. May be:

  • mapping (cartesian grid)
  • list of parameter dicts
  • callable that yields parameter dicts given a context
name str | None

Optional short name for this spec; defaults to control_cls.__name__ if omitted.

search_strategy Literal['grid', 'random']

Strategy for traversing vars when it is a mapping or a sequence. Either "grid" (use all points) or "random" (sample a subset).

num_samples int | None

Number of points to sample when search_strategy="random" and vars is a mapping or sequence; ignored when vars is callable.

seed int | None

Optional random seed used when search_strategy="random".

Source code in steerability/algorithms/core/specs.py
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
@dataclass(slots=True)
class ControlSpec:
    """Specification for a parameterized steering control.

    A `ControlSpec` describes a control class plus a search space over its constructor arguments. The sweep layer
    (`core/sweeps.py`, and `SteeringEval` above it) uses it to instantiate control instances for different
    hyperparameter settings.

    Attributes:
        control_cls: The steering control class to instantiate.
        params: Fixed constructor arguments for the control.
        vars: Optional search space over additional constructor arguments. May be:

            - mapping (cartesian grid)
            - list of parameter dicts
            - callable that yields parameter dicts given a context
        name: Optional short name for this spec; defaults to `control_cls.__name__` if omitted.
        search_strategy: Strategy for traversing `vars` when it is a mapping or a sequence. Either `"grid"` (use all
            points) or `"random"` (sample a subset).
        num_samples: Number of points to sample when `search_strategy="random"` and `vars` is a mapping or sequence;
            ignored when `vars` is callable.
        seed: Optional random seed used when `search_strategy="random"`.
    """

    control_cls: type
    params: Mapping[str, Any] = field(default_factory=dict)
    vars: Space | None = None
    name: str | None = None
    search_strategy: Literal["grid", "random"] = "grid"
    num_samples: int | None = None
    seed: int | None = None

    def iter_points(self, context: dict) -> Iterable[dict[str, Any]]:
        """Iterate over local search points for this spec.

        Args:
            context: Context dictionary; passed through to functional `vars` if `vars` is callable.

        Yields:
            Parameter dictionaries (possibly empty) that will be merged into `params` when constructing a concrete
            control instance.
        """
        search_space = self.vars

        # no search space
        if search_space is None:
            yield {}
            return

        # forward the context
        if callable(search_space):
            yield from search_space(context)  # callable controls sampling
            return

        # Mapping[str, Sequence[Any]]: potentially large cartesian product
        if isinstance(search_space, Mapping):
            param_names = list(search_space.keys())
            param_values = [list(search_space[name]) for name in param_names]

            if any(len(vals) == 0 for vals in param_values):
                return

            sizes = [len(vals) for vals in param_values]
            n_points = math.prod(sizes)

            # GRID SEARCH: iterate over the cartesian product
            if (
                self.search_strategy == "grid"
                or self.num_samples is None
                or self.num_samples >= n_points
            ):
                for combo in itertools.product(*param_values):
                    yield dict(zip(param_names, combo))
                return

            # RANDOM SEARCH: sample indices
            rng = random.Random(self.seed)
            k = min(self.num_samples, n_points)
            index_samples = rng.sample(range(n_points), k)

            # decode (flat) index into a combination of parameter choices
            for flat_index in index_samples:
                idx = flat_index
                indices_per_dim: list[int] = []
                for size in reversed(sizes):
                    indices_per_dim.append(idx % size)
                    idx //= size
                indices_per_dim.reverse()

                values = [param_values[dim][indices_per_dim[dim]] for dim in range(len(param_names))]
                yield dict(zip(param_names, values))
            return

        # Sequence[Mapping[str, Any]]: explicit list of parameter dicts
        combinations = [dict(param_dict) for param_dict in search_space]

        if (
            self.search_strategy == "random"
            and self.num_samples is not None
            and self.num_samples < len(combinations)
        ):
            rng = random.Random(self.seed)
            combinations = rng.sample(combinations, self.num_samples)

        for combination in combinations:
            yield combination

    def resolve_params(self, chosen: dict[str, Any], context: dict) -> dict[str, Any]:
        """Compute the full kwargs for this control at a given search point.
        """
        local_context = dict(context)
        local_context["search_params"] = chosen

        resolved_params = {
            key: (value(local_context) if callable(value) else value)
            for key, value in self.params.items()
        }

        resolved_params.update(chosen)
        return resolved_params
control_cls instance-attribute
name = None class-attribute instance-attribute
num_samples = None class-attribute instance-attribute
params = field(default_factory=dict) class-attribute instance-attribute
search_strategy = 'grid' class-attribute instance-attribute
seed = None class-attribute instance-attribute
vars = None class-attribute instance-attribute
iter_points(context)

Iterate over local search points for this spec.

Parameters:

Name Type Description Default
context dict

Context dictionary; passed through to functional vars if vars is callable.

required

Yields:

Type Description
Iterable[dict[str, Any]]

Parameter dictionaries (possibly empty) that will be merged into params when constructing a concrete

Iterable[dict[str, Any]]

control instance.

Source code in steerability/algorithms/core/specs.py
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
def iter_points(self, context: dict) -> Iterable[dict[str, Any]]:
    """Iterate over local search points for this spec.

    Args:
        context: Context dictionary; passed through to functional `vars` if `vars` is callable.

    Yields:
        Parameter dictionaries (possibly empty) that will be merged into `params` when constructing a concrete
        control instance.
    """
    search_space = self.vars

    # no search space
    if search_space is None:
        yield {}
        return

    # forward the context
    if callable(search_space):
        yield from search_space(context)  # callable controls sampling
        return

    # Mapping[str, Sequence[Any]]: potentially large cartesian product
    if isinstance(search_space, Mapping):
        param_names = list(search_space.keys())
        param_values = [list(search_space[name]) for name in param_names]

        if any(len(vals) == 0 for vals in param_values):
            return

        sizes = [len(vals) for vals in param_values]
        n_points = math.prod(sizes)

        # GRID SEARCH: iterate over the cartesian product
        if (
            self.search_strategy == "grid"
            or self.num_samples is None
            or self.num_samples >= n_points
        ):
            for combo in itertools.product(*param_values):
                yield dict(zip(param_names, combo))
            return

        # RANDOM SEARCH: sample indices
        rng = random.Random(self.seed)
        k = min(self.num_samples, n_points)
        index_samples = rng.sample(range(n_points), k)

        # decode (flat) index into a combination of parameter choices
        for flat_index in index_samples:
            idx = flat_index
            indices_per_dim: list[int] = []
            for size in reversed(sizes):
                indices_per_dim.append(idx % size)
                idx //= size
            indices_per_dim.reverse()

            values = [param_values[dim][indices_per_dim[dim]] for dim in range(len(param_names))]
            yield dict(zip(param_names, values))
        return

    # Sequence[Mapping[str, Any]]: explicit list of parameter dicts
    combinations = [dict(param_dict) for param_dict in search_space]

    if (
        self.search_strategy == "random"
        and self.num_samples is not None
        and self.num_samples < len(combinations)
    ):
        rng = random.Random(self.seed)
        combinations = rng.sample(combinations, self.num_samples)

    for combination in combinations:
        yield combination
resolve_params(chosen, context)

Compute the full kwargs for this control at a given search point.

Source code in steerability/algorithms/core/specs.py
128
129
130
131
132
133
134
135
136
137
138
139
140
def resolve_params(self, chosen: dict[str, Any], context: dict) -> dict[str, Any]:
    """Compute the full kwargs for this control at a given search point.
    """
    local_context = dict(context)
    local_context["search_params"] = chosen

    resolved_params = {
        key: (value(local_context) if callable(value) else value)
        for key, value in self.params.items()
    }

    resolved_params.update(chosen)
    return resolved_params

steering_pipeline

Core steering pipeline for composing and applying multiple LLM control methods.

logger = logging.getLogger(__name__) module-attribute

SteeringPipeline dataclass

Main steering pipeline for applying various control methods to Hugging Face causal language models.

Enables application of structural, state, input, and output controls in a coordinated manner. Controls are applied in a fixed bottom-up order during steering, then used together during generation.

Workflow:

  1. Instantiate with a base model checkpoint and/or control objects.
  2. Call steer() once to apply all controls in order (structural, input, state, output).
  3. Use generate() for inference with steering applied, accepting str, list[str], chat, or tensor input.

Parameters:

Name Type Description Default
model_name_or_path str or Path

HuggingFace model hub name or local directory, loaded during steer(). Optional when model is supplied or a structural control returns the model.

None
controls Sequence[StructuralControl | StateControl | InputControl | OutputControl]

Controls for the steering pipeline. Every category accepts any number of controls, applied in list order. The output category additionally accepts at most one enabled DecodingDriver (the decode loop does not compose). An omitted category is an empty list; an omitted output category uses the default decoding driver (model.generate).

()
tokenizer_name_or_path str

Tokenizer location. Defaults to model_name_or_path.

None
device_map str or dict[str, int]

Device map (passed to transformers.AutoModelForCausalLM.from_pretrained). Defaults to "auto". Cannot be used together with device parameter. Placement arguments apply only when the pipeline loads the model itself; a preloaded model keeps its own placement.

'auto'
device (device, str)

Device (passed to model's .to() method). When specified, device_map must remain at its default value of "auto".

None
hf_model_kwargs dict

Extra keyword arguments passed to transformers.AutoModelForCausalLM.from_pretrained.

dict()
trust_remote_code bool

Trust remote code when loading the tokenizer. Defaults to False. To trust remote code for the model, pass trust_remote_code=True via hf_model_kwargs.

False
lazy_init bool

Deprecated and inert: construction never loads the model; acquisition happens in steer(), and a structural control may supply the model when model_name_or_path is None.

False
backend BackendSpec | str

The pipeline's backend. Defaults to the in-process Hugging Face backend described by this pipeline's own construction arguments. A "vllm" spec boots an offline engine (requires the vllm extra) and a "vllm-serve" spec targets a running vLLM server; check() reports which enabled controls the backend supports, plus the steer plan, before anything executes.

None
fit str

Fit venue policy. "auto" (default) fits through the backend's session where its capture surface serves the fit; "in_process" forces every fit onto a staged in-process model, for engine-independent numerics.

'auto'
model PreTrainedModel

Preloaded model to steer, reused as-is by steer(); device is set from it at construction.

None
tokenizer PreTrainedTokenizerBase

Preloaded tokenizer, normalized with ensure_pad_token and injected into controls at construction.

None

Raises:

Type Description
RuntimeError

If generate() is called before steer()

ValueError

If more than one enabled DecodingDriver is supplied or required arguments are missing

Note:

  • Every category accepts multiple controls, applied in list order. An omitted category is an empty list; an omitted output category uses the pipeline's default decoding driver.
  • Controls with a tokenizer attribute will have it auto-injected if not already set
  • Construction is cheap: on the Hugging Face backend model is None until steer() unless a preloaded model= was passed.
  • On engine backends, model is non-None only while the staged in-process model exists during the steer phase; the stage is freed before the engine boots.

For the state category, list order in controls defines the composition surface. List order sets steer() order, hook registration order, and execution order for hooks on the same module. PyTorch forward hooks chain, so a later hook receives the previous hook's returned output and pre-hooks chain likewise on inputs. Combinations that do not commute, such as ablate after add versus add after ablate, therefore produce order-sensitive results. A gated or condition-scoring control placed after another observes activations already edited at earlier layers by upstream list entries.

For the input category, adaptation runs in two phases. On chat input, every control's adapt_messages runs in list order over the message batch (each non-None return feeds the next control); the result is templated and tokenized once, then every control whose adapt_messages returned None runs its token-level adapt in list order over the token stream. On text/tensor input there is no message phase; every control's adapt runs in list order. List order is authoritative within each phase, but the message phase structurally precedes the token phase: with [TokenOnlyControl, MessageLevelControl] on chat input, the message-level control's effect lands first even though it is listed second (tokens do not exist before templating). Place semantic rewriters (e.g. PRewrite, CPO, GEPA) before surface formatting (e.g. FewShot), since a rewriter trained on bare instructions degrades on exemplar-prepended input.

For the structural category, steer() threads the model through the controls in list order: each control receives the previous control's returned model (and the possibly mutated tokenizer). Nothing implicit happens between stages (no adapter merging, no embedding-resize reconciliation); stage compatibility is the caller's responsibility.

Source code in steerability/algorithms/core/steering_pipeline.py
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
@dataclass(slots=True, eq=False, weakref_slot=True)
class SteeringPipeline:
    """Main steering pipeline for applying various control methods to Hugging Face causal language models.

    Enables application of structural, state, input, and output controls in a coordinated manner.
    Controls are applied in a fixed bottom-up order during steering, then used together during generation.

    Workflow:

    1. Instantiate with a base model checkpoint and/or control objects.
    2. Call `steer()` once to apply all controls in order (structural, input, state, output).
    3. Use `generate()` for inference with steering applied, accepting str, list[str], chat, or tensor input.

    Args:
        model_name_or_path (str or pathlib.Path, optional): HuggingFace model hub name or local directory,
            loaded during `steer()`. Optional when `model` is supplied or a structural control
            returns the model.
        controls (Sequence[StructuralControl | StateControl | InputControl | OutputControl], optional):
            Controls for the steering pipeline. Every category accepts any number of controls,
            applied in list order. The output category additionally accepts at most one enabled
            `DecodingDriver` (the decode loop does not compose). An omitted category is an empty
            list; an omitted output category uses the default decoding driver (`model.generate`).
        tokenizer_name_or_path (str, optional): Tokenizer location. Defaults to `model_name_or_path`.
        device_map (str or dict[str, int], optional): Device map (passed to
            `transformers.AutoModelForCausalLM.from_pretrained`). Defaults to `"auto"`.
            Cannot be used together with `device` parameter. Placement arguments apply only
            when the pipeline loads the model itself; a preloaded `model` keeps its own placement.
        device (torch.device, str, optional): Device (passed to model's `.to()` method).
            When specified, `device_map` must remain at its default value of `"auto"`.
        hf_model_kwargs (dict, optional): Extra keyword arguments passed to
            `transformers.AutoModelForCausalLM.from_pretrained`.
        trust_remote_code (bool, optional): Trust remote code when loading the tokenizer. Defaults to
            `False`. To trust remote code for the model, pass `trust_remote_code=True` via `hf_model_kwargs`.
        lazy_init (bool, optional): Deprecated and inert: construction never loads the model;
            acquisition happens in `steer()`, and a structural control may supply the model
            when `model_name_or_path` is None.
        backend (BackendSpec | str, optional): The pipeline's backend. Defaults to the
            in-process Hugging Face backend described by this pipeline's own construction
            arguments. A `"vllm"` spec boots an offline engine (requires the `vllm` extra) and
            a `"vllm-serve"` spec targets a running vLLM server; `check()` reports which
            enabled controls the backend supports, plus the steer plan, before anything
            executes.
        fit (str, optional): Fit venue policy. `"auto"` (default) fits through the backend's
            session where its capture surface serves the fit; `"in_process"` forces every fit
            onto a staged in-process model, for engine-independent numerics.
        model (PreTrainedModel, optional): Preloaded model to steer, reused as-is by `steer()`;
            `device` is set from it at construction.
        tokenizer (PreTrainedTokenizerBase, optional): Preloaded tokenizer, normalized with
            `ensure_pad_token` and injected into controls at construction.

    Raises:
        RuntimeError: If `generate()` is called before `steer()`
        ValueError: If more than one enabled `DecodingDriver` is supplied or required arguments are missing

    Note:

    - Every category accepts multiple controls, applied in list order. An omitted category is
        an empty list; an omitted output category uses the pipeline's default decoding driver.
    - Controls with a `tokenizer` attribute will have it auto-injected if not already set
    - Construction is cheap: on the Hugging Face backend `model` is None until `steer()`
        unless a preloaded `model=` was passed.
    - On engine backends, `model` is non-None only while the staged in-process model exists
        during the steer phase; the stage is freed before the engine boots.

    For the state category, list order in `controls` defines the composition surface. List order sets
    `steer()` order, hook registration order, and execution order for hooks on the same module. PyTorch
    forward hooks chain, so a later hook receives the previous hook's returned output and pre-hooks chain
    likewise on inputs. Combinations that do not commute, such as ablate after add versus add after
    ablate, therefore produce order-sensitive results. A gated or condition-scoring control placed after
    another observes activations already edited at earlier layers by upstream list entries.

    For the input category, adaptation runs in two phases. On chat input, every control's
    `adapt_messages` runs in list order over the message batch (each non-None return feeds the next
    control); the result is templated and tokenized once, then every control whose `adapt_messages`
    returned None runs its token-level `adapt` in list order over the token stream. On text/tensor
    input there is no message phase; every control's `adapt` runs in list order. List order is
    authoritative within each phase, but the message phase structurally precedes the token phase:
    with `[TokenOnlyControl, MessageLevelControl]` on chat input, the message-level control's effect
    lands first even though it is listed second (tokens do not exist before templating). Place
    semantic rewriters (e.g. `PRewrite`, `CPO`, `GEPA`) before surface formatting (e.g. `FewShot`),
    since a rewriter trained on bare instructions degrades on exemplar-prepended input.

    For the structural category, `steer()` threads the model through the controls in list order:
    each control receives the previous control's returned model (and the possibly mutated tokenizer).
    Nothing implicit happens between stages (no adapter merging, no embedding-resize reconciliation);
    stage compatibility is the caller's responsibility.
    """

    # construction args
    model_name_or_path: str | Path | None = None
    controls: Sequence[StructuralControl | StateControl | InputControl | OutputControl] = ()
    tokenizer_name_or_path: str | None = None
    device_map: str | dict[str, int] | int | torch.device | None = "auto"
    device: torch.device | str | None = None
    hf_model_kwargs: dict = field(default_factory=dict)
    trust_remote_code: bool = False
    lazy_init: bool = False
    backend: BackendSpec | str | None = None
    fit: Literal["auto", "in_process"] = "auto"
    model: PreTrainedModel | None = field(default=None, repr=False)
    tokenizer: PreTrainedTokenizerBase | None = field(default=None, repr=False)

    # steer-filled fields
    _support_report: SupportReport | None = field(init=False, default=None, repr=False)
    _backends: dict = field(init=False, default_factory=dict, repr=False)
    _structural_artifacts: tuple = field(init=False, default=(), repr=False)
    _lowered_state: dict = field(init=False, default_factory=dict, repr=False)

    structural_controls: list[StructuralControl] = field(init=False)
    input_controls: list[InputControl] = field(init=False)
    state_controls: list[StateControl] = field(init=False)
    output_controls: list[OutputControl] = field(init=False)

    _is_steered: bool = field(default=False, init=False, repr=False)
    _prompt_warnings: PromptWarnings = field(default_factory=PromptWarnings, init=False, repr=False)

    def __post_init__(self) -> None:

        # sort/validate the supplied steering methods
        controls_merged = merge_controls(self.controls)
        self.structural_controls = controls_merged["structural_controls"]
        self.input_controls = controls_merged["input_controls"]
        self.state_controls = controls_merged["state_controls"]
        self.output_controls = controls_merged["output_controls"]

        if self.fit not in ("auto", "in_process"):
            raise ValueError(f"fit must be 'auto' or 'in_process'; got {self.fit!r}.")
        if self.device is not None and self.device_map != "auto":
            raise ValueError("Cannot specify both `device` and `device_map`.")

        # construction performs no I/O; steer() acquires the model and tokenizer
        spec = self._resolve_backend_spec(self.backend)
        if (
            spec.kind == "huggingface"
            and self.model is None
            and self.model_name_or_path is None
            and not self.structural_controls
        ):
            raise ValueError(
                "`model_name_or_path` or `model` must be provided unless a structural control "
                "supplies the model."
            )

        if self.model is not None:
            self.device = self.model.device
        if self.tokenizer is not None:
            self.tokenizer = ensure_pad_token(self.tokenizer)
        self._inject_tokenizer()

    def _resolve_client_tokenizer(self, spec: BackendSpec) -> None:
        """Resolve the client-side tokenizer for an engine backend, if not already set.

        The source is `tokenizer_name_or_path`, the spec's `tokenizer_name_or_path` option,
        the spec's model reference, or `model_name_or_path`, in that order. Leaves the
        tokenizer unset when no source is available or the source does not resolve, so the
        backend's own error (a missing optional dependency, a bad model reference) surfaces
        as the authoritative failure.
        """
        if self.tokenizer is not None:
            return
        source = (
            self.tokenizer_name_or_path
            or spec.get_option("tokenizer_name_or_path")
            or spec.model
            or (str(self.model_name_or_path) if self.model_name_or_path is not None else None)
        )
        if source is None:
            return
        try:
            self.tokenizer = ensure_pad_token(AutoTokenizer.from_pretrained(
                source, trust_remote_code=self.trust_remote_code,
            ))
        except Exception:
            logger.debug("Client tokenizer resolution from %r failed.", source, exc_info=True)
            return
        self._inject_tokenizer()

    def _load_in_process_model(self, model_ref: str | Path) -> None:
        """Load `model_ref` with the constructor's placement knobs and bind it as `model`."""
        logger.info("Loading model %s.", model_ref)
        started = time.monotonic()
        if self.device is not None:
            self.model = AutoModelForCausalLM.from_pretrained(
                model_ref,
                **self.hf_model_kwargs,
            )
            self.model = self.model.to(self.device)
            self.device = self.model.device
        else:
            self.model = AutoModelForCausalLM.from_pretrained(
                model_ref,
                device_map=self.device_map,
                **self.hf_model_kwargs,
            )
            self.device = self.model.device
        logger.info("Loaded model %s in %.0fs.", model_ref, time.monotonic() - started)

    @property
    def supports_batching(self) -> bool:
        """Return True if all enabled controls in this pipeline are batch-safe.

        The default decoding driver is batch-safe, so an empty `output_controls` list is vacuously
        true and does not constrain batching.
        """
        controls = (
            *self.structural_controls,
            *self.input_controls,
            *self.state_controls,
            *self.output_controls,
        )
        return all(
            getattr(control, "supports_batching", False)
            for control in controls
            if control.enabled
        )

    def _inject_tokenizer(self) -> None:
        """Attach the pipeline tokenizer to every control exposing an unset `tokenizer`."""
        if self.tokenizer is None:
            return
        for control in (
            *self.structural_controls, *self.input_controls,
            *self.state_controls, *self.output_controls,
        ):
            if hasattr(control, "tokenizer") and getattr(control, "tokenizer", None) is None:
                control.tokenizer = self.tokenizer

    def _warn_on_runtime_kwargs_overlap(self) -> None:
        """Validate the enabled controls' `RUNTIME_KWARGS_SCHEMA` declarations and warn
        (UserWarning, once) when two or more enabled controls declare the same variable name.

        All controls read from the single `runtime_kwargs` dict passed to `generate()`, so a shared
        name means one value feeds several controls. Sharing can be intentional, hence a warning
        rather than an error; disagreeing declarations of one name are a contract conflict and
        raise instead.

        Raises:
            ValueError: If an entry declares an invalid `scope`, or two controls declare one name
                with a different `scope` or `type`.
        """
        controls = (*self.structural_controls, *self.input_controls, *self.state_controls, *self.output_controls)
        runtime_kwargs_schema(controls)
        declared: dict[str, list[str]] = {}
        for control in controls:
            if not control.enabled:
                continue
            for entry in getattr(control, "RUNTIME_KWARGS_SCHEMA", []):
                name = entry.get("name")
                if name:
                    declared.setdefault(name, []).append(type(control).__name__)
        overlaps = {name: owners for name, owners in declared.items() if len(owners) > 1}
        if overlaps:
            details = "; ".join(
                f"'{name}' is declared by {', '.join(owners)}" for name, owners in overlaps.items()
            )
            warnings.warn(
                f"Multiple controls declare the same runtime_kwargs variable: {details}. "
                "All controls read from the one runtime_kwargs dict, so these controls will share "
                "the same value at inference time.",
                UserWarning,
            )

    def _resolve_backend_spec(
        self, value: BackendSpec | str | None, param_name: str = "backend",
    ) -> BackendSpec:
        """Resolve a backend argument to a `BackendSpec`.

        None and `"huggingface"` resolve to the implicit in-process spec derived from this
        pipeline's construction arguments; another known kind name resolves to a bare spec of
        that kind carrying the pipeline's model reference; a `BackendSpec` passes through.

        Args:
            value: The backend argument to resolve.
            param_name: The caller's parameter name, used in the `TypeError` message so it names
                the argument the caller passed.

        Raises:
            TypeError: If `value` is neither None, a known kind name, nor a `BackendSpec`.
        """
        if isinstance(value, BackendSpec):
            return value
        model = str(self.model_name_or_path) if self.model_name_or_path is not None else None
        if value is None or value == "huggingface":
            return BackendSpec(
                kind="huggingface",
                model=model,
                options={
                    "hf_model_kwargs": self.hf_model_kwargs,
                    "device_map": self.device_map,
                    "trust_remote_code": self.trust_remote_code,
                    "tokenizer_name_or_path": self.tokenizer_name_or_path,
                },
            )
        if isinstance(value, str) and value in KNOWN_BACKEND_KINDS:
            return BackendSpec(kind=value, model=model)
        raise TypeError(
            f"{param_name} must be a BackendSpec or one of {', '.join(KNOWN_BACKEND_KINDS)}; got {value!r}."
        )

    def _backend_for(self, spec: BackendSpec):
        """The backend instance for `spec`, constructed on first use and cached by spec.

        The `"huggingface"` kind adopts this pipeline's live model and tokenizer (providers are
        re-read per access, so structural replacement stays visible); other kinds construct from
        the spec and receive the pipeline's structural artifacts to serve.
        """
        backend = self._backends.get(spec)
        if backend is None:
            backend_cls = resolve_backend_class(spec)
            if spec.kind == "huggingface":
                backend = backend_cls.adopt(spec, lambda: self.model, lambda: self.tokenizer)
            else:
                backend = backend_cls(spec, artifacts=self._structural_artifacts)
            self._backends[spec] = backend
        return backend

    def release_backends(self) -> None:
        """Release every backend this pipeline constructed and empty the cache.

        Subsequent operations construct fresh backends against the same specs. Lowered
        intervention entries and staged artifacts persist, so a released pipeline remains usable
        at the cost of re-booting engines on next use. Release is idempotent. Engine-owning
        backends shut down deterministically.
        """
        backends, self._backends = self._backends, {}
        for backend in backends.values():
            try:
                backend.release()
            except Exception:
                logger.warning("Backend release failed", exc_info=True)

    def __enter__(self) -> "SteeringPipeline":
        """Return the pipeline for use as a context manager."""
        return self

    def __exit__(self, exc_type, exc, tb) -> None:
        """Release the pipeline's backends on exit; does not suppress exceptions."""
        self.release_backends()

    def check(self, backend: BackendSpec | str | None = None) -> SupportReport:
        """Evaluate every enabled control's backend requirements and compute the steer plan.

        Runs automatically at `steer()` (which raises on generate-phase failures) and is
        callable standalone against any backend. Disabled controls, including the pipeline's
        default identity controls, never gate a backend and do not appear in the report. The
        returned report's `plan` states, per enabled control and per fit artifact, where the
        steer phase will run each step; the plan is a pure function of the declarations and
        the spec, so the same configuration always yields the same verdicts and plan.

        Args:
            backend: Backend to evaluate against. Defaults to the pipeline's `backend`, then
                to the implicit in-process backend.

        Returns:
            The `SupportReport` with the steer plan and one failure per unsupported
            (control, phase) pair.
        """
        spec = self._resolve_backend_spec(backend if backend is not None else self.backend)
        capabilities = capabilities_for_spec(spec)
        controls = (*self.structural_controls, *self.input_controls, *self.state_controls, *self.output_controls)
        report = evaluate_support(controls, spec, capabilities)
        plan = self._compute_plan(controls, spec, capabilities)
        return replace(report, plan=plan)

    def _compute_plan(
        self,
        controls: Sequence[Any],
        spec: BackendSpec,
        capabilities: BackendCapabilities,
    ) -> SteerPlan:
        """The steer plan for `controls` on `spec`; pure, with no I/O and no weights.

        Venues on the Hugging Face backend are all `"live"`. On engine backends, `MODULE`
        steps stage, `FACTS` and `ROLLOUTS` steps run on the engine session, and `CAPTURE`
        steps run on the session when the spec statically advertises `HIDDEN_CAPTURE` and
        `fit == "auto"`, else on the stage. A fit's venue is its owning step's. A calibrated
        fit whose venue departs from its engine read venue (the `fit="in_process"` flag, or a
        spec whose capture surface is statically absent) contributes a notice.
        """
        in_process = spec.kind == "huggingface"
        capture_advertised = Capability.HIDDEN_CAPTURE in capabilities.atoms
        steps: list[PlannedStep] = []
        fits: list[PlannedFit] = []
        notices: list[str] = []
        for control in controls:
            if not getattr(control, "enabled", True):
                continue
            access = control.steer_access()
            if in_process:
                venue = "live"
            elif access >= ModelAccess.MODULE:
                venue = "stage"
            elif access == ModelAccess.CAPTURE:
                venue = "session" if (capture_advertised and self.fit == "auto") else "stage"
            else:
                venue = "session"
            name = type(control).__name__
            steps.append(PlannedStep(control=name, access=access, venue=venue))
            for artifact, artifact_class in control.steer_fits():
                fits.append(PlannedFit(
                    control=name, artifact=artifact, artifact_class=artifact_class, venue=venue,
                ))
                crossing = venue == "stage" and (self.fit == "in_process" or not capture_advertised)
                if artifact_class == "calibrated" and not in_process and crossing:
                    reason = (
                        "fit='in_process'" if self.fit == "in_process"
                        else "capture is unavailable on this backend"
                    )
                    notices.append(
                        f"{artifact} for {name} is scale-calibrated and will be read on "
                        f"backend kind '{spec.kind}', but is fitted in process ({reason}); "
                        "calibrated thresholds may shift across execution boundaries."
                    )
        return SteerPlan(
            steps=tuple(steps),
            fits=tuple(fits),
            stages=any(step.venue == "stage" for step in steps),
            notices=tuple(notices),
        )

    def steer(self, **steer_kwargs) -> None:
        """Apply all steering controls per the steer plan.

        Executes each control's steer() method in a fixed bottom-up order: structural -> input -> state -> output,
        and in list order within each category. If any control's steer() method returns a
        PreTrainedModel instance, it replaces the current model for subsequent controls, so
        structural controls thread the model through in list order.

        Before any control runs, `check()` evaluates the configured backend and raises on any
        generate-phase failure. Each control's `steer()` receives `session=`, a session scoped
        to its declared `steer_access()`, unless the caller supplied its own `session` keyword,
        and receives the live model only at `ModelAccess.MODULE`. On the Hugging Face backend
        every step runs against the live model in one phase. On engine backends the plan's
        stage-venued steps run first on a temporary in-process model that is freed before the
        engine boots (exported artifacts are the handoff), then the session-venued steps run
        through the engine session. The only channel between one control's steer and another's
        is the pipeline model, and every control that can touch it runs in the stage phase, so
        per-phase global order preserves the composition semantics of the single-phase order.

        A failed steer releases any backends it constructed before re-raising, so it does not
        leave an engine behind and a retried steer re-boots. A repeated call on an
        already-steered pipeline is a no-op.

        Warns:
            UserWarning: If two or more enabled controls declare the same `RUNTIME_KWARGS_SCHEMA`
                variable name, if a calibrated fit is fitted in process while its artifact is
                read on an engine, or if engine capture fails the steer-time smoke test and
                fitting degrades to a staged in-process model.

        Raises:
            RuntimeError: If no model is available after steering, or the staged in-process
                model was retained past the steer stage.
            ValueError: If an enabled control's `RUNTIME_KWARGS_SCHEMA` entry declares an invalid
                `scope`, or two enabled controls declare one runtime kwarg with a different
                `scope` or `type`.
            UnsupportedPipelineError: If any enabled control is unsupported at the generate
                phase on the configured backend.
            ModuleNotFoundError: If a configured backend kind requires an optional dependency
                that is not installed (e.g. the `vllm` extra).
        """
        if self._is_steered:
            return

        try:
            self._warn_on_runtime_kwargs_overlap()

            spec = self._resolve_backend_spec(self.backend)
            report = self.check()
            report.raise_for("generate")
            self._support_report = report

            if spec.kind == "huggingface":
                self._steer_in_process(spec, report.plan, steer_kwargs)
            else:
                self._resolve_client_tokenizer(spec)
                self._steer_on_engine(spec, report.plan, steer_kwargs)

            if self.tokenizer is None:
                repo = getattr(self.model, "name_or_path", None)
                source = repo or self._structural_out_path()
                if source is None:
                    raise RuntimeError("Failed to resolve tokenizer post‑steer.")
                try:
                    self.tokenizer = AutoTokenizer.from_pretrained(
                        source,
                        trust_remote_code=self.trust_remote_code,
                    )
                    self.tokenizer = ensure_pad_token(self.tokenizer)

                except Exception as exception:
                    raise RuntimeError("Failed to resolve tokenizer post‑steer.") from exception

            self._inject_tokenizer()

            # a spec-consuming backend gets every enabled control's interventions lowered now,
            # so inexpressible configurations fail before the first generate and artifacts are
            # staged once
            self._lowered_state = lower_state_controls(
                self.state_controls, self._backend_for(spec), capabilities_for_spec(spec),
            )
        except Exception:
            self.release_backends()
            raise

        # return steered pipeline
        self._is_steered = True

    def to_spipe(self, *, freeze: bool | None = None, model_ref: str | None = None) -> "SPipe":
        """Serialize this pipeline as an `SPipe`.

        A steered pipeline freezes by default: each enabled control's steer-time products are
        exported into a content-addressed artifact store and its resolved constructor form is
        recorded alongside the recipe, so the loaded pipeline steers cheaply and model-free.
        An unsteered pipeline yields a recipe-only spipe; `freeze=False` forces recipe-only
        from a steered pipeline.

        Args:
            freeze: Freeze the resolution. Defaults to the pipeline's steered state.
            model_ref: Explicit model reference recorded in the spipe, overriding
                `model_name_or_path` and the loaded model's `name_or_path`.

        Returns:
            The built `SPipe` (call its `save()` to write a `.spipe` file or directory).

        Raises:
            SpipeSaveError: If no model reference is resolvable, a control is unregistered or
                cannot serialize, or a control cannot freeze.
        """
        from steerability.spipe.freeze import build_spipe

        return build_spipe(self, freeze=freeze, model_ref=model_ref)

    def _enabled_controls(self) -> list:
        """Enabled controls in global steer order (structural, input, state, output)."""
        return [
            control
            for control in (
                *self.structural_controls, *self.input_controls,
                *self.state_controls, *self.output_controls,
            )
            if getattr(control, "enabled", True)
        ]

    def _run_control_steer(self, control, access: ModelAccess, venue_session, steer_kwargs) -> None:
        """Run one control's steer with a session scoped to `access` and the model gated by it.

        The live model travels only through the `model=` argument, and only at
        `ModelAccess.MODULE`. A caller-supplied `session` keyword overrides the scoped
        session. A returned `nn.Module` replaces the pipeline model for subsequent controls.
        """
        steer_fn = getattr(control, "steer", None)
        if not callable(steer_fn):
            return
        kwargs = steer_kwargs
        if "session" not in kwargs:
            scoped = ScopedSession(venue_session, type(control).__name__, access)
            kwargs = {**kwargs, "session": scoped}
        model = self.model if access >= ModelAccess.MODULE else None
        control_name = type(control).__name__
        logger.info("Steering %s (access=%s).", control_name, access.name.lower())
        started = time.monotonic()
        maybe_new_model = steer_fn(model, tokenizer=self.tokenizer, **kwargs)
        logger.info("Steered %s in %.1fs.", control_name, time.monotonic() - started)
        if isinstance(maybe_new_model, nn.Module):
            self.model = maybe_new_model

    def _steer_in_process(self, spec: BackendSpec, plan: SteerPlan, steer_kwargs: dict) -> None:
        """Run every enabled control's steer against the live model, in one phase.

        Acquires the model and tokenizer first when the constructor received references
        rather than preloaded objects, so controls see both during their steer.
        """
        if self.model is None and self.model_name_or_path is not None:
            self._load_in_process_model(self.model_name_or_path)
        if self.tokenizer is None:
            source = self.tokenizer_name_or_path or self.model_name_or_path
            if source is not None:
                self.tokenizer = ensure_pad_token(AutoTokenizer.from_pretrained(
                    source, trust_remote_code=self.trust_remote_code,
                ))
                self._inject_tokenizer()
        backend = self._backend_for(spec)
        controls = self._enabled_controls()
        with backend.open_session() as session:
            for control, step in zip(controls, plan.steps):
                self._run_control_steer(control, step.access, session, steer_kwargs)

        self._structural_artifacts = self._collect_structural_artifacts(spec)

        if self.model is None:
            raise RuntimeError(
                "No model is available after steering. Either provide a base model "
                "(`model_name_or_path` or `model=`) or ensure a `StructuralControl` returns one."
            )

    def _steer_on_engine(self, spec: BackendSpec, plan: SteerPlan, steer_kwargs: dict) -> None:
        """Run the staged steer: stage-venued steps on a temporary in-process model, freed
        before the engine boots, then session-venued steps through the engine session.

        When the plan assigned any fit to engine capture, one single-prompt capture smoke test
        runs before any session-venued steer; on failure the affected controls' venues revise
        to the stage (the engine is released first, so weights and engine never coexist) and
        the remaining session-venued steers run against a re-booted engine. No control's
        steer() ever runs twice.
        """
        controls = self._enabled_controls()
        steps = {id(control): step for control, step in zip(controls, plan.steps)}
        stage_controls = [c for c in controls if steps[id(c)].venue == "stage"]
        session_controls = [c for c in controls if steps[id(c)].venue == "session"]

        if plan.stages:
            for notice in plan.notices:
                warnings.warn(notice, UserWarning)
            self._run_stage(spec, stage_controls, steps, steer_kwargs)

        backend = self._backend_for(spec)
        session_fitters = {planned.control for planned in plan.fits if planned.venue == "session"}
        fit_controls = [c for c in session_controls if type(c).__name__ in session_fitters]

        session = backend.open_session()
        try:
            if fit_controls:
                error = capture_smoke_failure(session, self.tokenizer)
                if error is not None:
                    warnings.warn(
                        f"Hidden-state capture on backend kind '{spec.kind}' failed at steer "
                        f"({error}); fitting degrades to a staged in-process model. Set "
                        "fit='in_process' to plan this from the start.",
                        UserWarning,
                    )
                    session.close()
                    self.release_backends()
                    self._run_stage(spec, fit_controls, steps, steer_kwargs)
                    session_controls = [c for c in session_controls if c not in fit_controls]
                    backend = self._backend_for(spec)
                    session = backend.open_session()
            for control in session_controls:
                self._run_control_steer(control, steps[id(control)].access, session, steer_kwargs)
        finally:
            session.close()

    def _run_stage(self, spec: BackendSpec, stage_controls, steps, steer_kwargs: dict) -> None:
        """Load the staged in-process model, run `stage_controls`' steers on it, collect
        structural artifacts, and free the stage.

        The stage is configured by the constructor's placement knobs and loads
        `spec.model` (or `model_name_or_path`). Structural returns thread through the stage,
        and the exported artifacts are the handoff to the engine.

        Raises:
            RuntimeError: If no model reference is available to load the stage from, or the
                staged model was retained past the stage by a control.
        """
        model_ref = spec.model or (
            str(self.model_name_or_path) if self.model_name_or_path is not None else None
        )
        if model_ref is None:
            raise RuntimeError(
                "The steer plan stages an in-process model, but neither the backend spec nor "
                "`model_name_or_path` names a model to load."
            )
        stage_spec = BackendSpec(
            kind="huggingface",
            model=model_ref,
            options={
                "hf_model_kwargs": self.hf_model_kwargs,
                "device_map": self.device_map,
                "trust_remote_code": self.trust_remote_code,
                "tokenizer_name_or_path": self.tokenizer_name_or_path,
            },
        )
        self._load_in_process_model(model_ref)
        stage_backend = resolve_backend_class(stage_spec).adopt(
            stage_spec, lambda: self.model, lambda: self.tokenizer,
        )
        try:
            with stage_backend.open_session() as stage_session:
                for control in stage_controls:
                    self._run_control_steer(
                        control, steps[id(control)].access, stage_session, steer_kwargs,
                    )
            if not self._structural_artifacts:
                self._structural_artifacts = self._collect_structural_artifacts(stage_spec)
        finally:
            stage_backend.release()
        if self.model is not None:
            ref = weakref.ref(self.model)
            self.model = None
            verify_stage_released(ref, self._enabled_controls())

    def _collect_structural_artifacts(self, spec: BackendSpec) -> tuple[Artifact, ...]:
        """Enabled structural controls' steer-time artifacts, provenance-stamped.

        Provenance carries the producing venue's spec hash (the stage spec on engine
        backends) and, when a live model is present, its fingerprint.
        """
        artifacts: list[Artifact] = []
        for control in self.structural_controls:
            if not control.enabled:
                continue
            exporter = getattr(control, "export_artifact", None)
            artifact = exporter() if callable(exporter) else None
            if artifact is not None:
                artifacts.append(artifact)
        if not artifacts:
            return ()

        model_fingerprint = None
        if self.model is not None:
            from steerability.algorithms.core.internals.fingerprint import (
                model_fingerprint as compute_model_fingerprint,
            )
            try:
                model_fingerprint = compute_model_fingerprint(self.model)
            except Exception:
                logger.debug("Model fingerprint unavailable for artifact provenance.")
        provenance = ArtifactProvenance(
            backend_spec_hash=spec.spec_hash,
            model_fingerprint=model_fingerprint,
        )
        return tuple(replace(artifact, provenance=provenance) for artifact in artifacts)

    def _structural_out_path(self) -> Path | None:
        """The last structural control's non-empty `args.out_path`, as a tokenizer-directory fallback.

        Scans `structural_controls` in reverse so the most recently produced artifact wins; controls
        without an `args` attribute or without `out_path` are skipped. When more than one control
        defines `out_path`, logs at info level which path won.
        """
        candidates = [
            (type(control).__name__, out_path)
            for control in self.structural_controls
            if (out_path := getattr(getattr(control, "args", None), "out_path", None))
        ]
        if not candidates:
            return None
        winner_name, winner_path = candidates[-1]
        if len(candidates) > 1:
            logger.info(
                "Multiple structural controls define out_path (%s); using %s from %s.",
                ", ".join(name for name, _ in candidates), winner_path, winner_name,
            )
        return Path(winner_path)

    @overload
    def generate(
            self,
            inputs: str,
            attention_mask: None = ...,
            runtime_kwargs: dict | None = ...,
            return_output: Literal[False] = ...,
            **gen_kwargs: Any,
    ) -> str: ...
    @overload
    def generate(
            self,
            inputs: list[str],
            attention_mask: None = ...,
            runtime_kwargs: dict | None = ...,
            return_output: Literal[False] = ...,
            **gen_kwargs: Any,
    ) -> list[str]: ...
    @overload
    def generate(
            self,
            *,
            text: str,
            runtime_kwargs: dict | None = ...,
            return_output: Literal[False] = ...,
            **gen_kwargs: Any,
    ) -> str: ...
    @overload
    def generate(
            self,
            *,
            text: Sequence[str],
            runtime_kwargs: dict | None = ...,
            return_output: Literal[False] = ...,
            **gen_kwargs: Any,
    ) -> list[str]: ...
    @overload
    def generate(
            self,
            *,
            messages: Sequence[Mapping],
            runtime_kwargs: dict | None = ...,
            return_output: Literal[False] = ...,
            **gen_kwargs: Any,
    ) -> str: ...
    @overload
    def generate(
            self,
            *,
            messages: Sequence[Sequence[Mapping]],
            runtime_kwargs: dict | None = ...,
            return_output: Literal[False] = ...,
            **gen_kwargs: Any,
    ) -> list[str]: ...
    @overload
    def generate(
            self,
            *,
            input_ids: torch.Tensor | list[int] | list[list[int]],
            attention_mask: torch.Tensor | None = ...,
            runtime_kwargs: dict | None = ...,
            return_output: Literal[False] = ...,
            **gen_kwargs: Any,
    ) -> torch.Tensor: ...
    @overload
    def generate(
            self,
            inputs: Any = ...,
            attention_mask: torch.Tensor | None = ...,
            runtime_kwargs: dict | None = ...,
            *,
            text: Any = ...,
            messages: Any = ...,
            input_ids: Any = ...,
            return_output: Literal[True],
            **gen_kwargs: Any,
    ) -> Output | list[Output]: ...
    @overload
    def generate(
            self,
            inputs: str | list[str] | None = ...,
            attention_mask: None = ...,
            runtime_kwargs: dict | None = ...,
            return_output: bool = ...,
            *,
            text: str | Sequence[str] | None = ...,
            messages: Sequence[Mapping] | Sequence[Sequence[Mapping]] | None = ...,
            **gen_kwargs: Any,
    ) -> str | list[str] | Output | list[Output]: ...
    @overload
    def generate(
            self,
            *,
            input_ids: torch.Tensor | list[int] | list[list[int]],
            attention_mask: torch.Tensor | None = ...,
            runtime_kwargs: dict | None = ...,
            return_output: bool = ...,
            **gen_kwargs: Any,
    ) -> torch.Tensor | Output | list[Output]: ...

    def generate(
            self,
            inputs: str | list[str] | None = None,
            attention_mask: torch.Tensor | None = None,
            runtime_kwargs: dict | None = None,
            return_output: bool = False,
            *,
            text: str | Sequence[str] | None = None,
            messages: Sequence[Mapping] | Sequence[Sequence[Mapping]] | None = None,
            input_ids: torch.Tensor | list[int] | list[list[int]] | None = None,
            **gen_kwargs: Any,
    ) -> str | list[str] | torch.Tensor | Output | list[Output]:
        """Generate with steering across text, chat, and token prompts.

        The prompt source is declared by keyword, with exactly one source per call:

        | Source | Tokenization | Default return type |
        | --- | --- | --- |
        | `text=` (`str`) | plain text | `str` |
        | `text=` (`Sequence[str]`) | batched plain text | `list[str]` |
        | `messages=` (one conversation) | `apply_chat_template` | `str` |
        | `messages=` (batch of conversations) | batched `apply_chat_template` | `list[str]` |
        | `input_ids=` (1-D tokens) | already tokenized; passed through | `torch.Tensor` |
        | `input_ids=` (2-D tokens) | already tokenized; passed through | `torch.Tensor` |

        Positional `str`/`list[str]` is accepted as a convenience for text prompts and behaves like
        `text=`; any other positional shape raises `TypeError`. With `return_output=True`, the return
        is always `Output` (single) or `list[Output]` (batched) regardless of source. The per-source
        methods `generate_text`, `generate_messages`, and `generate_tokens` expose the same behavior
        with source-specific signatures and document each source's rules.

        The decoded text returns carry exactly one candidate per prompt. Requesting multiple
        candidates (`num_return_sequences` or `n` greater than 1) with `text=` or `messages=`
        raises `ValueError` unless `return_output=True`, where `Output.output_ids` holds one row
        per candidate and `Output.finish_reasons` one reason per candidate. The token return
        (`input_ids=`) carries candidates in its shape, `[batch * n, gen_len]` with each prompt's
        candidates contiguous, matching `model.generate`.

        Args:
            inputs: Positional convenience for text prompts (`str` or `list[str]`), behaving like
                `text=`. Any other positional shape raises `TypeError`; use the keywords below.
            attention_mask: Attention mask, valid only with `input_ids=`.
            runtime_kwargs: Per-generation parameters for controls (e.g., `{"substrings": [...]}`).
            return_output: If True, return one or more `Output` objects instead of decoded text /
                token IDs.
            text: Text prompt as a `str` or a sequence of `str`.
            messages: Chat prompt as one conversation (a sequence of mappings) or a batch (a sequence
                of sequences of mappings).
            input_ids: Token prompt as a 1-D/2-D integer tensor, `list[int]`, or `list[list[int]]`.
            **gen_kwargs: Generation parameters in `model.generate` vocabulary, normalized
                through `GenerationParams` and executed by the inference backend's session
                (unlisted keys pass through in process and raise on API backends). Two keys are
                reserved and consumed here rather than forwarded to the backend:

                    - `return_full_sequence: bool` to include the prompt in the returned token IDs.
                        For a padded batch the returned rows are in left-packed layout
                        (`[pads, prompt, continuation]`), the layout the continuation was
                        generated from.
                    - `chat_template_kwargs: dict` forwarded to `apply_chat_template` after the
                        pipeline-owned template kwargs. Valid only with `messages=` (pairing it with
                        `text=`/`input_ids=` raises `TypeError`); it may not name any pipeline-owned
                        template kwarg (`return_tensors`, `padding`, `add_generation_prompt`,
                        `return_dict`, else `ValueError`). An empty mapping is a no-op. The toolkit
                        does not interpret the mapping; keys are model-family specific (e.g.
                        `enable_thinking`), and models whose templates expose no such switch are
                        unaffected.

        Returns:
            See dispatch table above.

        Raises:
            RuntimeError: If `steer()` has not yet been called.
            TypeError: If no prompt source or more than one is provided, if a source fails
                validation, if `attention_mask` is paired with `text=`/`messages=`, if
                `chat_template_kwargs` is paired with `text=`/`input_ids=`, or if
                `chat_template_kwargs` is not a mapping.
            ValueError: If a token tensor is not 1-D/2-D, nested token lists are ragged, a text/
                chat sequence is empty, `chat_template_kwargs` names a pipeline-owned template
                argument, or multiple candidates per prompt (`num_return_sequences`/`n` greater
                than 1) are requested on a decoded text return without `return_output=True`.
        """
        if not self._is_steered:
            raise RuntimeError("Must call `.steer()` before `.generate()`.")

        runtime_kwargs = runtime_kwargs or {}
        return_full_sequence = bool(gen_kwargs.pop("return_full_sequence", False))
        chat_template_kwargs = gen_kwargs.pop("chat_template_kwargs", None)

        if chat_template_kwargs is not None:
            if not isinstance(chat_template_kwargs, Mapping):
                raise TypeError(
                    "chat_template_kwargs must be a mapping of chat-template keyword arguments; got "
                    f"{type(chat_template_kwargs).__name__}."
                )
            reserved = {"return_tensors", "padding", "add_generation_prompt", "return_dict"}
            collisions = reserved & set(chat_template_kwargs)
            if collisions:
                names = ", ".join(sorted(collisions))
                raise ValueError(
                    f"chat_template_kwargs may not override pipeline-owned template arguments: {names}."
                )

        kind, payload = resolve_generate_source(inputs, text, messages, input_ids)

        # attention_mask pairing
        if attention_mask is not None and kind != "tokens":
            raise TypeError(
                "attention_mask is only valid with token input (input_ids=); it is derived "
                "automatically for text= and messages=."
            )

        # chat_template_kwargs pairing
        if chat_template_kwargs is not None and kind != "messages":
            raise TypeError(
                "chat_template_kwargs is only valid with chat input (messages=); text= and input_ids= "
                "are already templated or template-free."
            )

        # candidate-count pairing: the decoded text return carries exactly one candidate per
        # prompt, so multiple candidates require the Output return or the token return
        if kind != "tokens" and not return_output:
            requested_n = gen_kwargs.get("n", gen_kwargs.get("num_return_sequences"))
            if isinstance(requested_n, int) and requested_n > 1:
                raise ValueError(
                    f"num_return_sequences={requested_n} requests multiple candidates per prompt, "
                    "but the decoded text return carries exactly one candidate per prompt; pass "
                    "return_output=True to receive every candidate (Output.output_ids holds one "
                    "row per candidate and Output.decode() decodes them all), or generate with "
                    "input_ids= for a [batch * n, gen_len] token return."
                )

        # resolve the prompt tensors per modality
        message_handled: set[int] = set()
        if kind == "text":
            prompt_input_ids, prompt_attention_mask, is_single = resolve_text_prompt(
                payload,
                input_controls=self.input_controls,
                tokenizer=self.tokenizer,
                warnings_state=self._prompt_warnings,
            )
        elif kind == "messages":
            prompt_input_ids, prompt_attention_mask, message_handled, is_single = resolve_messages_prompt(
                payload,
                runtime_kwargs,
                input_controls=self.input_controls,
                tokenizer=self.tokenizer,
                chat_template_kwargs=chat_template_kwargs,
            )
        else:  # tokens
            prompt_input_ids, prompt_attention_mask, is_single = resolve_token_prompt(
                payload,
                attention_mask,
                input_controls=self.input_controls,
                warnings_state=self._prompt_warnings,
            )

        return self._execute_generation(
            prompt_input_ids=prompt_input_ids,
            prompt_attention_mask=prompt_attention_mask,
            message_handled=message_handled,
            decode_text=(kind != "tokens"),
            is_single=is_single,
            runtime_kwargs=runtime_kwargs,
            return_output=return_output,
            return_full_sequence=return_full_sequence,
            gen_kwargs=gen_kwargs,
        )

    @overload
    def generate_text(
            self,
            text: str,
            *,
            runtime_kwargs: dict | None = ...,
            return_output: Literal[False] = ...,
            return_full_sequence: bool = ...,
            **gen_kwargs: Any,
    ) -> str: ...
    @overload
    def generate_text(
            self,
            text: Sequence[str],
            *,
            runtime_kwargs: dict | None = ...,
            return_output: Literal[False] = ...,
            return_full_sequence: bool = ...,
            **gen_kwargs: Any,
    ) -> list[str]: ...
    @overload
    def generate_text(
            self,
            text: str | Sequence[str],
            *,
            runtime_kwargs: dict | None = ...,
            return_output: Literal[True],
            return_full_sequence: bool = ...,
            **gen_kwargs: Any,
    ) -> Output | list[Output]: ...
    @overload
    def generate_text(
            self,
            text: str | Sequence[str],
            *,
            runtime_kwargs: dict | None = ...,
            return_output: bool = ...,
            return_full_sequence: bool = ...,
            **gen_kwargs: Any,
    ) -> str | list[str] | Output | list[Output]: ...

    def generate_text(
            self,
            text: str | Sequence[str],
            *,
            runtime_kwargs: dict | None = None,
            return_output: bool = False,
            return_full_sequence: bool = False,
            **gen_kwargs: Any,
    ) -> str | list[str] | Output | list[Output]:
        """Generate from plain-text prompts.

        A `str` returns `str`; a sequence of `str` returns `list[str]` (`Output` or
        `list[Output]` with `return_output=True`). Input controls apply at token level only;
        `adapt_messages` does not fire on text input. The decoded return carries exactly one
        candidate per prompt; `num_return_sequences`/`n` greater than 1 raises `ValueError`
        unless `return_output=True`.

        Args:
            text: Text prompt as a `str` or a sequence of `str`.
            runtime_kwargs: Per-generation parameters for controls.
            return_output: If True, return `Output` (single) or `list[Output]` (batched).
            return_full_sequence: If True, include the prompt in the returned token IDs.
                Returned ids exclude the prompt by default; do not slice the result by
                prompt length.
            **gen_kwargs: Generation parameters, as for `generate()`.

        Returns:
            `str`, `list[str]`, `Output`, or `list[Output]`.
        """
        gen_kwargs["return_full_sequence"] = return_full_sequence
        return self.generate(
            text=text, runtime_kwargs=runtime_kwargs, return_output=return_output, **gen_kwargs,
        )

    @overload
    def generate_messages(
            self,
            messages: Sequence[Mapping],
            *,
            chat_template_kwargs: Mapping | None = ...,
            runtime_kwargs: dict | None = ...,
            return_output: Literal[False] = ...,
            return_full_sequence: bool = ...,
            **gen_kwargs: Any,
    ) -> str: ...
    @overload
    def generate_messages(
            self,
            messages: Sequence[Sequence[Mapping]],
            *,
            chat_template_kwargs: Mapping | None = ...,
            runtime_kwargs: dict | None = ...,
            return_output: Literal[False] = ...,
            return_full_sequence: bool = ...,
            **gen_kwargs: Any,
    ) -> list[str]: ...
    @overload
    def generate_messages(
            self,
            messages: Sequence[Mapping] | Sequence[Sequence[Mapping]],
            *,
            chat_template_kwargs: Mapping | None = ...,
            runtime_kwargs: dict | None = ...,
            return_output: Literal[True],
            return_full_sequence: bool = ...,
            **gen_kwargs: Any,
    ) -> Output | list[Output]: ...
    @overload
    def generate_messages(
            self,
            messages: Sequence[Mapping] | Sequence[Sequence[Mapping]],
            *,
            chat_template_kwargs: Mapping | None = ...,
            runtime_kwargs: dict | None = ...,
            return_output: bool = ...,
            return_full_sequence: bool = ...,
            **gen_kwargs: Any,
    ) -> str | list[str] | Output | list[Output]: ...

    def generate_messages(
            self,
            messages: Sequence[Mapping] | Sequence[Sequence[Mapping]],
            *,
            chat_template_kwargs: Mapping | None = None,
            runtime_kwargs: dict | None = None,
            return_output: bool = False,
            return_full_sequence: bool = False,
            **gen_kwargs: Any,
    ) -> str | list[str] | Output | list[Output]:
        """Generate from chat prompts through the tokenizer's chat template.

        One conversation (a sequence of mappings) returns `str`; a batch (a sequence of
        sequences of mappings) returns `list[str]` (`Output` or `list[Output]` with
        `return_output=True`). Every input control's `adapt_messages` runs before templating;
        controls whose `adapt_messages` returns None run their token-level `adapt` after
        tokenization, so each control applies exactly once per call. The decoded return
        carries exactly one candidate per prompt; `num_return_sequences`/`n` greater than 1
        raises `ValueError` unless `return_output=True`.

        Args:
            messages: One conversation or a batch of conversations.
            chat_template_kwargs: Extra keyword arguments forwarded to `apply_chat_template`
                after the pipeline-owned template kwargs. May not name a pipeline-owned
                template kwarg (`return_tensors`, `padding`, `add_generation_prompt`,
                `return_dict`). The toolkit does not interpret the mapping; keys are
                model-family specific (e.g. `enable_thinking`).
            runtime_kwargs: Per-generation parameters for controls.
            return_output: If True, return `Output` (single) or `list[Output]` (batched).
            return_full_sequence: If True, include the prompt in the returned token IDs.
                Returned ids exclude the prompt by default; do not slice the result by
                prompt length.
            **gen_kwargs: Generation parameters, as for `generate()`.

        Returns:
            `str`, `list[str]`, `Output`, or `list[Output]`.
        """
        gen_kwargs["return_full_sequence"] = return_full_sequence
        if chat_template_kwargs is not None:
            gen_kwargs["chat_template_kwargs"] = chat_template_kwargs
        return self.generate(
            messages=messages, runtime_kwargs=runtime_kwargs, return_output=return_output,
            **gen_kwargs,
        )

    @overload
    def generate_tokens(
            self,
            input_ids: torch.Tensor | list[int] | list[list[int]],
            attention_mask: torch.Tensor | None = ...,
            *,
            runtime_kwargs: dict | None = ...,
            return_output: Literal[False] = ...,
            return_full_sequence: bool = ...,
            **gen_kwargs: Any,
    ) -> torch.Tensor: ...
    @overload
    def generate_tokens(
            self,
            input_ids: torch.Tensor | list[int] | list[list[int]],
            attention_mask: torch.Tensor | None = ...,
            *,
            runtime_kwargs: dict | None = ...,
            return_output: Literal[True],
            return_full_sequence: bool = ...,
            **gen_kwargs: Any,
    ) -> Output | list[Output]: ...
    @overload
    def generate_tokens(
            self,
            input_ids: torch.Tensor | list[int] | list[list[int]],
            attention_mask: torch.Tensor | None = ...,
            *,
            runtime_kwargs: dict | None = ...,
            return_output: bool = ...,
            return_full_sequence: bool = ...,
            **gen_kwargs: Any,
    ) -> torch.Tensor | Output | list[Output]: ...

    def generate_tokens(
            self,
            input_ids: torch.Tensor | list[int] | list[list[int]],
            attention_mask: torch.Tensor | None = None,
            *,
            runtime_kwargs: dict | None = None,
            return_output: bool = False,
            return_full_sequence: bool = False,
            **gen_kwargs: Any,
    ) -> torch.Tensor | Output | list[Output]:
        """Generate from already-tokenized prompts.

        Returns a `torch.Tensor` of continuation ids (`Output` or `list[Output]` with
        `return_output=True`). Input controls apply at token level only; `adapt_messages`
        does not fire on token input. With `num_return_sequences`/`n` greater than 1 the
        returned tensor is `[batch * n, gen_len]` with each prompt's candidates contiguous,
        matching `model.generate`.

        Args:
            input_ids: Token prompt as a 1-D/2-D integer tensor, `list[int]`, or
                `list[list[int]]`.
            attention_mask: Attention mask matching `input_ids`, or None to derive it.
            runtime_kwargs: Per-generation parameters for controls.
            return_output: If True, return `Output` (single) or `list[Output]` (batched).
            return_full_sequence: If True, include the prompt in the returned token IDs.
                Returned ids exclude the prompt by default; do not slice the result by
                prompt length.
            **gen_kwargs: Generation parameters, as for `generate()`.

        Returns:
            `torch.Tensor`, `Output`, or `list[Output]`.
        """
        gen_kwargs["return_full_sequence"] = return_full_sequence
        return self.generate(
            input_ids=input_ids, attention_mask=attention_mask, runtime_kwargs=runtime_kwargs,
            return_output=return_output, **gen_kwargs,
        )

    def _execute_generation(
            self,
            prompt_input_ids: torch.Tensor,
            prompt_attention_mask: torch.Tensor | None,
            message_handled: frozenset[int] | set[int],
            *,
            decode_text: bool,
            is_single: bool,
            runtime_kwargs: dict,
            return_output: bool,
            return_full_sequence: bool,
            gen_kwargs: dict,
    ) -> str | list[str] | torch.Tensor | Output | list[Output]:
        """Run the shared generation tail from prompt tensors through the shaped return.

        Applies the token-level input-control chain, then left-packs the steered prompt tensors
        so hook assembly, per-item prompts, driver inputs, and full-sequence returns share the
        left-packed layout the sessions execute batched forwards in. Merges sampling-expressible
        output controls into the call's `GenerationParams` and configures state hooks. With the
        default decoding driver, each prompt row becomes a `GenerationItem` executed by the
        inference backend's session; an explicit `DecodingDriver` instead runs client-side
        under the state-control hook context with `session=` passed for its rollouts. The
        return is then shaped per modality: decoded continuation text truncates at the first
        stop string, and the prompt slice is removed by default (`return_full_sequence=False`
        returns continuation tokens only).

        Args:
            prompt_input_ids: Prompt token IDs [seq_len] or [batch, seq_len] before the token-level
                `adapt` chain.
            prompt_attention_mask: Attention mask matching `prompt_input_ids`, or None to derive it.
            message_handled: `id()`s of input controls already handled at message level; their
                token-level `adapt` is skipped.
            decode_text: If True, decode the returned IDs to `str`/`list[str]`; if False, return the
                token tensor.
            is_single: If True, the caller passed a single (non-batched) prompt, so unwrap the batch
                dimension in the return.
            runtime_kwargs: Per-call parameters forwarded to input, state, and output controls.
            return_output: If True, return `Output` (single) or `list[Output]` (batched) regardless
                of `decode_text`.
            return_full_sequence: If True, include the prompt in the returned token IDs.
            gen_kwargs: Generation parameters forwarded to the decoding driver.

        Returns:
            `str` or `list[str]` when `decode_text` is True, `torch.Tensor` when False, or
            `Output`/`list[Output]` when `return_output` is True.
        """
        # input controls (token-level adapt chain) + normalize
        device = self.model.device if self.model is not None else torch.device("cpu")
        steered_input_ids, steered_attention_mask = prepare_inputs(
            prompt_input_ids,
            prompt_attention_mask,
            input_controls=self.input_controls,
            tokenizer=self.tokenizer,
            device=device,
            runtime_kwargs=runtime_kwargs,
            message_handled=frozenset(message_handled),
            warnings_state=self._prompt_warnings,
        )

        # left-pack for positional alignment in causal models; the sessions left-pack every
        # batched forward, and the hook runtime captures the prompt mask and prompt lengths
        # here, so hooks, per-item prompts, and full-sequence returns must share that layout
        steered_input_ids, steered_attention_mask = to_left_pad(
            steered_input_ids, steered_attention_mask
        )

        # sampling-expressible output controls lower to generation parameters for this call
        lowered = lowered_contributions(self.output_controls, runtime_kwargs)
        skip_ids = frozenset(lowered)

        spec = self._resolve_backend_spec(self.backend)
        backend = self._backend_for(spec)
        decoding_driver = resolve_decoding_driver(self.output_controls)
        inference_capabilities = capabilities_for_spec(spec)
        hooks_in_process = Capability.IN_PROCESS_TORCH in inference_capabilities.atoms
        has_enabled_state = any(control.enabled for control in self.state_controls)

        # state-control entry selection per backend: an in-process backend gets hooks built
        # once per logical generation; an intervention-capable backend gets exported specs. On
        # the in-process path under seed_scope="item", distinct per-item derived seeds run
        # serially in the session, so hooks are computed per row there rather than once on the
        # batch; under seed_scope="dispatch" the seeded dispatch batches, so batch hooks are kept.
        state_entry_rows: list[tuple[HookEntry, ...]] | None = None
        state_entries: tuple[StateControlEntry, ...] = ()
        if decoding_driver is not None:
            state_entries = collect_state_entries(
                self.state_controls, steered_input_ids, runtime_kwargs,
                attention_mask=steered_attention_mask, hooks_in_process=hooks_in_process,
                lowered_state=self._lowered_state, backend=backend,
                intervention_kinds=inference_capabilities.intervention_kinds,
                model=self.model, **gen_kwargs
            )
        elif not hooks_in_process:
            if has_enabled_state:
                state_entries = collect_state_entries(
                    self.state_controls, steered_input_ids, runtime_kwargs,
                    attention_mask=steered_attention_mask, hooks_in_process=hooks_in_process,
                    lowered_state=self._lowered_state, backend=backend,
                    intervention_kinds=inference_capabilities.intervention_kinds,
                    model=self.model, **gen_kwargs
                )
        elif (
            gen_kwargs.get("seed") is not None
            and gen_kwargs.get("seed_scope", "item") == "item"
            and steered_input_ids.size(0) > 1
            and has_enabled_state
        ):
            state_entry_rows = per_item_state_entries(
                self.state_controls, steered_input_ids, steered_attention_mask, runtime_kwargs,
                model=self.model, **gen_kwargs
            )
        else:
            state_entries = collect_state_entries(
                self.state_controls, steered_input_ids, runtime_kwargs,
                attention_mask=steered_attention_mask, hooks_in_process=hooks_in_process,
                lowered_state=self._lowered_state, backend=backend,
                intervention_kinds=inference_capabilities.intervention_kinds,
                model=self.model, **gen_kwargs
            )

        driver_generated_tokens: int | None = None
        with backend.open_session() as session:
            if decoding_driver is not None:
                # client-side driver path: composed stacks, session-hosted hooks for the span
                # of the decode, rollouts through a SteeredSession
                logits_processors, stopping_criteria = compose_stacks(
                    self.output_controls, steered_input_ids, runtime_kwargs,
                    steered_attention_mask, gen_kwargs, skip_ids=skip_ids,
                )
                params = GenerationParams.from_gen_kwargs(**gen_kwargs)
                for contribution in lowered.values():
                    params = merge_lowered_params(params, contribution)
                # in process, the session hosts this generation's hooks for the whole decode,
                # so rollouts through the session and auxiliary forwards on the live model are
                # steered alike and the SteeredSession injects nothing (ambient hooks already
                # cover its items); on spec-consuming backends the SteeredSession injects a
                # rollout variant of each lowered entry whose prompt-relative scopes are
                # rewritten to absolute positions at the generation's original prompt boundary
                driver_rollout_entries: tuple = ()
                if state_entries and hooks_in_process:
                    applied = session.entries_applied(state_entries)
                else:
                    applied = contextlib.nullcontext()
                    if state_entries:
                        driver_rollout_entries = rollout_entries(
                            state_entries, steered_input_ids, steered_attention_mask,
                        )
                driver_session = SteeredSession(session, driver_rollout_entries)
                with applied:
                    full_output_ids = decoding_driver.decode(
                        input_ids=steered_input_ids,
                        attention_mask=steered_attention_mask,
                        model=self.model,
                        logits_processors=logits_processors,
                        stopping_criteria=stopping_criteria,
                        runtime_kwargs=runtime_kwargs,
                        session=driver_session,
                        **params.to_gen_kwargs(),
                    )
                driver_generated_tokens = driver_session.generated_tokens
                prompt_len = steered_input_ids.size(1)
                new_tokens = full_output_ids[:, prompt_len:]
                reasons = infer_finish_reasons(
                    new_tokens,
                    {"max_new_tokens": params.max_new_tokens},
                    eos_token_id=self.tokenizer.eos_token_id,
                    pad_token_id=self.tokenizer.pad_token_id,
                    stop_strings=params.stop_strings,
                    stop_token_ids=params.stop_token_ids,
                    tokenizer=self.tokenizer,
                )
            else:
                # default path: per-prompt items executed by the session; on backends hosting
                # structured outputs natively, declarative constraints lower in place of their
                # live processors
                constraint_sources: dict[int, ConstraintSource] = {}
                processor_specs: dict[int, ProcessorSpecEntry] = {}
                if not hooks_in_process:
                    constraint_sources = constraint_contributions(self.output_controls, runtime_kwargs)
                    processor_specs = processor_spec_contributions(
                        self.output_controls, runtime_kwargs, inference_capabilities,
                    )
                output_entries = collect_output_entries(
                    self.output_controls, steered_input_ids, runtime_kwargs,
                    attention_mask=steered_attention_mask,
                    skip_ids=skip_ids | frozenset(constraint_sources) | frozenset(processor_specs),
                    **gen_kwargs,
                )
                if constraint_sources or processor_specs:
                    output_entries = output_entries + tuple(
                        ConstraintEntry(source=source) for source in constraint_sources.values()
                    ) + tuple(processor_specs.values())
                user_processors = gen_kwargs.pop("logits_processor", None) or []
                user_criteria = gen_kwargs.pop("stopping_criteria", None) or []
                params = GenerationParams.from_gen_kwargs(**gen_kwargs)
                for contribution in lowered.values():
                    params = merge_lowered_params(params, contribution)
                if user_processors or user_criteria:
                    extra = dict(params.extra)
                    if user_processors:
                        extra["logits_processor"] = user_processors
                    if user_criteria:
                        extra["stopping_criteria"] = user_criteria
                    params = replace(params, extra=extra)

                items = [
                    GenerationItem(
                        prompt=PreparedPrompt.from_token_ids(
                            steered_input_ids[i:i + 1], steered_attention_mask[i:i + 1],
                        ),
                        state_entries=state_entry_rows[i] if state_entry_rows is not None else state_entries,
                        output_entries=output_entries,
                    )
                    for i in range(steered_input_ids.size(0))
                ]
                results = session.generate(items, params)
                new_tokens, reasons = self._assemble_item_outputs(results)
                num_candidates = params.n or 1
                if return_full_sequence:
                    repeated = steered_input_ids.repeat_interleave(num_candidates, dim=0)
                    full_output_ids = torch.cat([repeated, new_tokens.to(repeated.device)], dim=1)
                else:
                    full_output_ids = None

        returned_ids = full_output_ids if return_full_sequence else new_tokens

        # shape return per modality + flag
        num_candidates = params.n or 1
        num_rows = new_tokens.size(0)
        # on the driver path split the wrapper's rollout-token total evenly across the returned
        # rows (remainder on the first row) so arm-level sums are preserved; the driverless path
        # leaves generated_tokens None and consumers fall back to the returned continuation count
        generated_per_row = _split_generated_tokens(driver_generated_tokens, num_rows)
        if return_output:
            if is_single:
                # one Output covers every candidate row, so it carries the full dispatch total
                return Output(
                    output_ids=new_tokens,
                    adapted_input_ids=steered_input_ids,
                    finish_reason=reasons[0],
                    finish_reasons=tuple(reasons),
                    generated_tokens=driver_generated_tokens,
                )
            return [
                Output(
                    output_ids=new_tokens[i:i + 1],
                    adapted_input_ids=steered_input_ids[i // num_candidates:i // num_candidates + 1],
                    finish_reason=reasons[i],
                    finish_reasons=(reasons[i],),
                    generated_tokens=generated_per_row[i],
                )
                for i in range(num_rows)
            ]

        if not decode_text:
            return returned_ids

        # text / chat → decode; decoded continuation text truncates at the first stop string
        decoded = self.tokenizer.decode(returned_ids, skip_special_tokens=True)
        if params.stop_strings and not return_full_sequence:
            decoded = [truncate_at_stop_strings(text, params.stop_strings) for text in decoded]
        if is_single:
            return decoded[0]
        return decoded

    def _assemble_item_outputs(self, results) -> tuple[torch.Tensor, list[str | None]]:
        """Stack item results into one `[batch * n, gen_len]` tensor plus flat per-row reasons.

        Rows pad to the longest continuation with the tokenizer's pad token, matching the
        right-padding a single batched `generate` call produces.
        """
        pad_token_id = self.tokenizer.pad_token_id if self.tokenizer.pad_token_id is not None else 0
        rows: list[torch.Tensor] = []
        reasons: list[str | None] = []
        for result in results:
            output = result.output
            rows.append(output.output_ids)
            if output.finish_reasons is not None:
                reasons.extend(output.finish_reasons)
            else:
                reasons.extend([output.finish_reason] * output.output_ids.size(0))
        max_len = max((row.size(1) for row in rows), default=0)
        padded = [
            torch.nn.functional.pad(row, (0, max_len - row.size(1)), value=pad_token_id)
            for row in rows
        ]
        return torch.cat(padded, dim=0), reasons

    def compute_logprobs(
            self,
            input_ids: list[int] | torch.LongTensor,
            attention_mask: torch.Tensor | None = None,
            ref_output_ids: list[int] | torch.LongTensor = None,
            runtime_kwargs: dict | None = None,
            **forward_kwargs: Any,
    ) -> torch.Tensor:
        """Compute per-token log-probabilities of ref_output_ids with structural, input, state, and output steering
        controls applied.

        Step-level output controls' logits processors are part of the steered next-token distribution, so they are
        applied here position-by-position (teacher-forced), for every enabled output control whose
        `include_in_scoring` is True. The exclusive mechanism has no scoring analogue: decoding drivers are not
        invoked and stopping criteria are not applied. A control opts out of scoring by setting
        `include_in_scoring=False` (e.g. processors too expensive to evaluate per reference position).

        Uses teacher forcing to compute log P(ref_t | steered_input, ref_1, ..., ref_{t-1}) for each
        token in the reference sequence.

        Decoder-only scoring executes through the inference backend's session as `ScoringItem`s.
        When all pipeline controls support batching, the items share one set of control entries
        and score in a single pass (inputs are left-padded internally for correct positional
        alignment); otherwise each item is prepared and scored sequentially. Encoder-decoder
        models score in process against the live model.

        Args:
            input_ids: Input token IDs as list or tensor [seq_len] or [batch, seq_len]
            attention_mask: Optional attention mask matching input_ids shape
            ref_output_ids: Reference tokens to score [ref_len] or [batch, ref_len]
            runtime_kwargs: Per-call parameters for controls (e.g., {"substrings": [...]})
            **forward_kwargs: Additional arguments passed to model forward pass

        Returns:
            torch.Tensor: Log probabilities of shape [batch, ref_len] for decoder-only models,
                or [batch, ref_len - 1] for encoder-decoder models (excludes first decoder token)

        Raises:
            RuntimeError: If steer() has not been called
            ValueError: If ref_output_ids is None
            UnsupportedPipelineError: If an enabled control is score-unsupported on the
                configured inference backend.
        """
        if not self._is_steered:
            raise RuntimeError("Must call `.steer()` before `.compute_logprobs()`.")
        if ref_output_ids is None:
            raise ValueError("`ref_output_ids` is required for `compute_logprobs()`.")
        if self._support_report is not None:
            self._support_report.raise_for("score")

        runtime_kwargs = runtime_kwargs or {}

        is_encoder_decoder = (
            self.model is not None and getattr(self.model.config, "is_encoder_decoder", False)
        )
        if is_encoder_decoder:
            return self._compute_logprobs_encoder_decoder(
                input_ids, attention_mask, ref_output_ids, runtime_kwargs, **forward_kwargs,
            )

        device = self.model.device if self.model is not None else torch.device("cpu")

        # normalize ref_output_ids
        if isinstance(ref_output_ids, list):
            ref_output_ids = torch.tensor(ref_output_ids, dtype=torch.long)
        if ref_output_ids.ndim == 1:
            ref_output_ids = ref_output_ids.unsqueeze(0)
        ref_output_ids = ref_output_ids.to(device)
        ref_len = ref_output_ids.size(1)

        spec = self._resolve_backend_spec(self.backend)
        backend = self._backend_for(spec)
        score_params = GenerationParams(extra=forward_kwargs)
        inference_capabilities = capabilities_for_spec(spec)
        hooks_in_process = Capability.IN_PROCESS_TORCH in inference_capabilities.atoms
        has_enabled_state = any(control.enabled for control in self.state_controls)

        # batched path (all controls are batch-safe): one left-packed pass over shared entries
        if self.supports_batching:
            steered_input_ids, steered_attention_mask = prepare_inputs(
                input_ids,
                attention_mask,
                input_controls=self.input_controls,
                tokenizer=self.tokenizer,
                device=device,
                runtime_kwargs=runtime_kwargs,
                warnings_state=self._prompt_warnings,
            )
            batch_size = steered_input_ids.size(0)
            if ref_output_ids.size(0) == 1 and batch_size > 1:
                ref_output_ids = ref_output_ids.expand(batch_size, -1)
            if ref_len == 0:
                return torch.zeros((batch_size, 0), device=device, dtype=torch.float32)

            # left-pad for correct positional alignment in causal models; with right-padding, pad
            # tokens between the real input and the appended ref tokens corrupt positional
            # encodings and the causal attention chain
            steered_input_ids, steered_attention_mask = to_left_pad(
                steered_input_ids, steered_attention_mask
            )
            state_entries = collect_state_entries(
                self.state_controls, steered_input_ids, runtime_kwargs,
                attention_mask=steered_attention_mask, hooks_in_process=hooks_in_process,
                lowered_state=self._lowered_state, backend=backend,
                intervention_kinds=inference_capabilities.intervention_kinds,
                model=self.model, **forward_kwargs,
            )
            output_entries = collect_output_entries(
                self.output_controls, steered_input_ids, runtime_kwargs,
                attention_mask=steered_attention_mask, for_scoring=True, **forward_kwargs,
            )
            items = [
                ScoringItem(
                    prompt=PreparedPrompt.from_token_ids(
                        steered_input_ids[i:i + 1], steered_attention_mask[i:i + 1],
                    ),
                    ref_output_ids=ref_output_ids[i:i + 1],
                    state_entries=state_entries,
                    output_entries=output_entries,
                )
                for i in range(batch_size)
            ]
            with backend.open_session() as session:
                return session.score(items, score_params)

        # sequential fallback (one or more controls do not support batching): per-item
        # preparation and entries, one scoring pass per item
        if isinstance(input_ids, list):
            input_ids = torch.tensor(input_ids, dtype=torch.long)
        if input_ids.ndim == 1:
            input_ids = input_ids.unsqueeze(0)
        input_ids = input_ids.to(device)

        if attention_mask is not None:
            if isinstance(attention_mask, list):
                attention_mask = torch.as_tensor(attention_mask, dtype=torch.long)
            if attention_mask.ndim == 1:
                attention_mask = attention_mask.unsqueeze(0)
            attention_mask = attention_mask.to(device)

        num_inputs = input_ids.size(0)
        if ref_output_ids.size(0) == 1 and num_inputs > 1:
            ref_output_ids = ref_output_ids.expand(num_inputs, -1)
        if ref_len == 0:
            return torch.zeros((num_inputs, 0), device=device, dtype=torch.float32)

        all_logprobs = []
        with backend.open_session() as session:
            for i in range(num_inputs):
                single_attention_mask = attention_mask[i:i + 1] if attention_mask is not None else None
                steered_input_ids, steered_attention_mask = prepare_inputs(
                    input_ids[i:i + 1],
                    single_attention_mask,
                    input_controls=self.input_controls,
                    tokenizer=self.tokenizer,
                    device=device,
                    runtime_kwargs=runtime_kwargs,
                    warnings_state=self._prompt_warnings,
                )
                state_entries = collect_state_entries(
                    self.state_controls, steered_input_ids, runtime_kwargs,
                    attention_mask=steered_attention_mask, hooks_in_process=hooks_in_process,
                    lowered_state=self._lowered_state, backend=backend,
                    intervention_kinds=inference_capabilities.intervention_kinds,
                    model=self.model, **forward_kwargs,
                )
                output_entries = collect_output_entries(
                    self.output_controls, steered_input_ids, runtime_kwargs,
                    attention_mask=steered_attention_mask, for_scoring=True, **forward_kwargs,
                )
                item = ScoringItem(
                    prompt=PreparedPrompt.from_token_ids(steered_input_ids, steered_attention_mask),
                    ref_output_ids=ref_output_ids[i:i + 1],
                    state_entries=state_entries,
                    output_entries=output_entries,
                )
                all_logprobs.append(session.score([item], score_params))
        return torch.cat(all_logprobs, dim=0)

    def _compute_logprobs_encoder_decoder(
            self,
            input_ids: list[int] | torch.LongTensor,
            attention_mask: torch.Tensor | None,
            ref_output_ids: list[int] | torch.LongTensor,
            runtime_kwargs: dict,
            **forward_kwargs: Any,
    ) -> torch.Tensor:
        """Teacher-forced scoring for encoder-decoder models, run in process against the live
        model (a batched pass when every control is batch-safe, else a sequential fallback)."""
        device = self.model.device

        spec = self._resolve_backend_spec(self.backend)
        backend = self._backend_for(spec)
        inference_capabilities = capabilities_for_spec(spec)
        hooks_in_process = Capability.IN_PROCESS_TORCH in inference_capabilities.atoms

        # normalize ref_output_ids
        if isinstance(ref_output_ids, list):
            ref_output_ids = torch.tensor(ref_output_ids, dtype=torch.long)
        if ref_output_ids.ndim == 1:
            ref_output_ids = ref_output_ids.unsqueeze(0)
        ref_output_ids = ref_output_ids.to(device)
        ref_len = ref_output_ids.size(1)

        # batched path (all controls are batch-safe)
        if self.supports_batching:
            # input controls
            steered_input_ids, attention_mask = prepare_inputs(
                input_ids,
                attention_mask,
                input_controls=self.input_controls,
                tokenizer=self.tokenizer,
                device=device,
                runtime_kwargs=runtime_kwargs,
                warnings_state=self._prompt_warnings,
            )
            batch_size = steered_input_ids.size(0)

            # broadcast single ref sequence across batch
            if ref_output_ids.size(0) == 1 and batch_size > 1:
                ref_output_ids = ref_output_ids.expand(batch_size, -1)

            if ref_len == 0:
                return torch.zeros((batch_size, 0), device=device, dtype=torch.float32)

            # state controls, hosted by the in-process session for the span of the forward
            state_entries = collect_state_entries(
                self.state_controls, steered_input_ids, runtime_kwargs,
                attention_mask=attention_mask, hooks_in_process=hooks_in_process,
                lowered_state=self._lowered_state, backend=backend,
                intervention_kinds=inference_capabilities.intervention_kinds,
                model=self.model, **forward_kwargs
            )
            with backend.open_session() as session, session.entries_applied(state_entries):
                with torch.no_grad():
                    outputs = self.model(
                        input_ids=steered_input_ids,
                        attention_mask=attention_mask,
                        decoder_input_ids=ref_output_ids,
                        **forward_kwargs,
                    )
                    # predicts ref[t+1] from ref[0:t]; logits[:, t, :] -> ref[t+1]
                    # logits[:, :-1, :] aligns with targets ref[:, 1:]
                    logits = outputs.logits[:, :-1, :]
                    target_ids = ref_output_ids[:, 1:]

                # apply output-control scoring processors under the steered distribution
                logits = apply_scoring_processors(
                    self.output_controls, logits, steered_input_ids, ref_output_ids,
                    runtime_kwargs, attention_mask, True, **forward_kwargs,
                )

                # compute logprobs
                logprobs = torch.log_softmax(logits, dim=-1)
                return logprobs.gather(dim=-1, index=target_ids.unsqueeze(-1)).squeeze(-1)

        # sequential fallback (one or more controls do not support batching)

        # normalize input_ids to 2D for indexing
        if isinstance(input_ids, list):
            input_ids = torch.tensor(input_ids, dtype=torch.long)
        if input_ids.ndim == 1:
            input_ids = input_ids.unsqueeze(0)
        input_ids = input_ids.to(device)

        if attention_mask is not None:
            if isinstance(attention_mask, list):
                attention_mask = torch.as_tensor(attention_mask, dtype=torch.long)
            if attention_mask.ndim == 1:
                attention_mask = attention_mask.unsqueeze(0)
            attention_mask = attention_mask.to(device)

        num_inputs = input_ids.size(0)

        # broadcast single ref sequence across batch
        if ref_output_ids.size(0) == 1 and num_inputs > 1:
            ref_output_ids = ref_output_ids.expand(num_inputs, -1)

        if ref_len == 0:
            return torch.zeros((num_inputs, 0), device=device, dtype=torch.float32)

        all_logprobs = []

        for i in range(num_inputs):
            single_input_ids = input_ids[i:i + 1]
            single_attention_mask = attention_mask[i:i + 1] if attention_mask is not None else None
            single_ref = ref_output_ids[i:i + 1]

            # input controls
            steered_input_ids, steered_attention_mask = prepare_inputs(
                single_input_ids,
                single_attention_mask,
                input_controls=self.input_controls,
                tokenizer=self.tokenizer,
                device=device,
                runtime_kwargs=runtime_kwargs,
                warnings_state=self._prompt_warnings,
            )

            # state controls, hosted by the in-process session for the span of the forward
            state_entries = collect_state_entries(
                self.state_controls, steered_input_ids, runtime_kwargs,
                attention_mask=steered_attention_mask, hooks_in_process=hooks_in_process,
                lowered_state=self._lowered_state, backend=backend,
                intervention_kinds=inference_capabilities.intervention_kinds,
                model=self.model, **forward_kwargs
            )
            with backend.open_session() as session, session.entries_applied(state_entries):
                with torch.no_grad():
                    outputs = self.model(
                        input_ids=steered_input_ids,
                        attention_mask=steered_attention_mask,
                        decoder_input_ids=single_ref,
                        **forward_kwargs,
                    )
                    logits = outputs.logits[:, :-1, :]
                    target_ids = single_ref[:, 1:]

                # apply output-control scoring processors under the steered distribution
                logits = apply_scoring_processors(
                    self.output_controls, logits, steered_input_ids, single_ref,
                    runtime_kwargs, steered_attention_mask, True, **forward_kwargs,
                )

                # compute logprobs
                logprobs = torch.log_softmax(logits, dim=-1)
                token_logprobs = logprobs.gather(dim=-1, index=target_ids.unsqueeze(-1)).squeeze(-1)
            all_logprobs.append(token_logprobs)

        return torch.cat(all_logprobs, dim=0)
backend = None class-attribute instance-attribute
controls = () class-attribute instance-attribute
device = None class-attribute instance-attribute
device_map = 'auto' class-attribute instance-attribute
fit = 'auto' class-attribute instance-attribute
hf_model_kwargs = field(default_factory=dict) class-attribute instance-attribute
input_controls = field(init=False) class-attribute instance-attribute
lazy_init = False class-attribute instance-attribute
model = field(default=None, repr=False) class-attribute instance-attribute
model_name_or_path = None class-attribute instance-attribute
output_controls = field(init=False) class-attribute instance-attribute
state_controls = field(init=False) class-attribute instance-attribute
structural_controls = field(init=False) class-attribute instance-attribute
supports_batching property

Return True if all enabled controls in this pipeline are batch-safe.

The default decoding driver is batch-safe, so an empty output_controls list is vacuously true and does not constrain batching.

tokenizer = field(default=None, repr=False) class-attribute instance-attribute
tokenizer_name_or_path = None class-attribute instance-attribute
trust_remote_code = False class-attribute instance-attribute
check(backend=None)

Evaluate every enabled control's backend requirements and compute the steer plan.

Runs automatically at steer() (which raises on generate-phase failures) and is callable standalone against any backend. Disabled controls, including the pipeline's default identity controls, never gate a backend and do not appear in the report. The returned report's plan states, per enabled control and per fit artifact, where the steer phase will run each step; the plan is a pure function of the declarations and the spec, so the same configuration always yields the same verdicts and plan.

Parameters:

Name Type Description Default
backend BackendSpec | str | None

Backend to evaluate against. Defaults to the pipeline's backend, then to the implicit in-process backend.

None

Returns:

Type Description
SupportReport

The SupportReport with the steer plan and one failure per unsupported

SupportReport

(control, phase) pair.

Source code in steerability/algorithms/core/steering_pipeline.py
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
def check(self, backend: BackendSpec | str | None = None) -> SupportReport:
    """Evaluate every enabled control's backend requirements and compute the steer plan.

    Runs automatically at `steer()` (which raises on generate-phase failures) and is
    callable standalone against any backend. Disabled controls, including the pipeline's
    default identity controls, never gate a backend and do not appear in the report. The
    returned report's `plan` states, per enabled control and per fit artifact, where the
    steer phase will run each step; the plan is a pure function of the declarations and
    the spec, so the same configuration always yields the same verdicts and plan.

    Args:
        backend: Backend to evaluate against. Defaults to the pipeline's `backend`, then
            to the implicit in-process backend.

    Returns:
        The `SupportReport` with the steer plan and one failure per unsupported
        (control, phase) pair.
    """
    spec = self._resolve_backend_spec(backend if backend is not None else self.backend)
    capabilities = capabilities_for_spec(spec)
    controls = (*self.structural_controls, *self.input_controls, *self.state_controls, *self.output_controls)
    report = evaluate_support(controls, spec, capabilities)
    plan = self._compute_plan(controls, spec, capabilities)
    return replace(report, plan=plan)
compute_logprobs(input_ids, attention_mask=None, ref_output_ids=None, runtime_kwargs=None, **forward_kwargs)

Compute per-token log-probabilities of ref_output_ids with structural, input, state, and output steering controls applied.

Step-level output controls' logits processors are part of the steered next-token distribution, so they are applied here position-by-position (teacher-forced), for every enabled output control whose include_in_scoring is True. The exclusive mechanism has no scoring analogue: decoding drivers are not invoked and stopping criteria are not applied. A control opts out of scoring by setting include_in_scoring=False (e.g. processors too expensive to evaluate per reference position).

Uses teacher forcing to compute log P(ref_t | steered_input, ref_1, ..., ref_{t-1}) for each token in the reference sequence.

Decoder-only scoring executes through the inference backend's session as ScoringItems. When all pipeline controls support batching, the items share one set of control entries and score in a single pass (inputs are left-padded internally for correct positional alignment); otherwise each item is prepared and scored sequentially. Encoder-decoder models score in process against the live model.

Parameters:

Name Type Description Default
input_ids list[int] | LongTensor

Input token IDs as list or tensor [seq_len] or [batch, seq_len]

required
attention_mask Tensor | None

Optional attention mask matching input_ids shape

None
ref_output_ids list[int] | LongTensor

Reference tokens to score [ref_len] or [batch, ref_len]

None
runtime_kwargs dict | None

Per-call parameters for controls (e.g., {"substrings": [...]})

None
**forward_kwargs Any

Additional arguments passed to model forward pass

{}

Returns:

Type Description
Tensor

torch.Tensor: Log probabilities of shape [batch, ref_len] for decoder-only models, or [batch, ref_len - 1] for encoder-decoder models (excludes first decoder token)

Raises:

Type Description
RuntimeError

If steer() has not been called

ValueError

If ref_output_ids is None

UnsupportedPipelineError

If an enabled control is score-unsupported on the configured inference backend.

Source code in steerability/algorithms/core/steering_pipeline.py
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
def compute_logprobs(
        self,
        input_ids: list[int] | torch.LongTensor,
        attention_mask: torch.Tensor | None = None,
        ref_output_ids: list[int] | torch.LongTensor = None,
        runtime_kwargs: dict | None = None,
        **forward_kwargs: Any,
) -> torch.Tensor:
    """Compute per-token log-probabilities of ref_output_ids with structural, input, state, and output steering
    controls applied.

    Step-level output controls' logits processors are part of the steered next-token distribution, so they are
    applied here position-by-position (teacher-forced), for every enabled output control whose
    `include_in_scoring` is True. The exclusive mechanism has no scoring analogue: decoding drivers are not
    invoked and stopping criteria are not applied. A control opts out of scoring by setting
    `include_in_scoring=False` (e.g. processors too expensive to evaluate per reference position).

    Uses teacher forcing to compute log P(ref_t | steered_input, ref_1, ..., ref_{t-1}) for each
    token in the reference sequence.

    Decoder-only scoring executes through the inference backend's session as `ScoringItem`s.
    When all pipeline controls support batching, the items share one set of control entries
    and score in a single pass (inputs are left-padded internally for correct positional
    alignment); otherwise each item is prepared and scored sequentially. Encoder-decoder
    models score in process against the live model.

    Args:
        input_ids: Input token IDs as list or tensor [seq_len] or [batch, seq_len]
        attention_mask: Optional attention mask matching input_ids shape
        ref_output_ids: Reference tokens to score [ref_len] or [batch, ref_len]
        runtime_kwargs: Per-call parameters for controls (e.g., {"substrings": [...]})
        **forward_kwargs: Additional arguments passed to model forward pass

    Returns:
        torch.Tensor: Log probabilities of shape [batch, ref_len] for decoder-only models,
            or [batch, ref_len - 1] for encoder-decoder models (excludes first decoder token)

    Raises:
        RuntimeError: If steer() has not been called
        ValueError: If ref_output_ids is None
        UnsupportedPipelineError: If an enabled control is score-unsupported on the
            configured inference backend.
    """
    if not self._is_steered:
        raise RuntimeError("Must call `.steer()` before `.compute_logprobs()`.")
    if ref_output_ids is None:
        raise ValueError("`ref_output_ids` is required for `compute_logprobs()`.")
    if self._support_report is not None:
        self._support_report.raise_for("score")

    runtime_kwargs = runtime_kwargs or {}

    is_encoder_decoder = (
        self.model is not None and getattr(self.model.config, "is_encoder_decoder", False)
    )
    if is_encoder_decoder:
        return self._compute_logprobs_encoder_decoder(
            input_ids, attention_mask, ref_output_ids, runtime_kwargs, **forward_kwargs,
        )

    device = self.model.device if self.model is not None else torch.device("cpu")

    # normalize ref_output_ids
    if isinstance(ref_output_ids, list):
        ref_output_ids = torch.tensor(ref_output_ids, dtype=torch.long)
    if ref_output_ids.ndim == 1:
        ref_output_ids = ref_output_ids.unsqueeze(0)
    ref_output_ids = ref_output_ids.to(device)
    ref_len = ref_output_ids.size(1)

    spec = self._resolve_backend_spec(self.backend)
    backend = self._backend_for(spec)
    score_params = GenerationParams(extra=forward_kwargs)
    inference_capabilities = capabilities_for_spec(spec)
    hooks_in_process = Capability.IN_PROCESS_TORCH in inference_capabilities.atoms
    has_enabled_state = any(control.enabled for control in self.state_controls)

    # batched path (all controls are batch-safe): one left-packed pass over shared entries
    if self.supports_batching:
        steered_input_ids, steered_attention_mask = prepare_inputs(
            input_ids,
            attention_mask,
            input_controls=self.input_controls,
            tokenizer=self.tokenizer,
            device=device,
            runtime_kwargs=runtime_kwargs,
            warnings_state=self._prompt_warnings,
        )
        batch_size = steered_input_ids.size(0)
        if ref_output_ids.size(0) == 1 and batch_size > 1:
            ref_output_ids = ref_output_ids.expand(batch_size, -1)
        if ref_len == 0:
            return torch.zeros((batch_size, 0), device=device, dtype=torch.float32)

        # left-pad for correct positional alignment in causal models; with right-padding, pad
        # tokens between the real input and the appended ref tokens corrupt positional
        # encodings and the causal attention chain
        steered_input_ids, steered_attention_mask = to_left_pad(
            steered_input_ids, steered_attention_mask
        )
        state_entries = collect_state_entries(
            self.state_controls, steered_input_ids, runtime_kwargs,
            attention_mask=steered_attention_mask, hooks_in_process=hooks_in_process,
            lowered_state=self._lowered_state, backend=backend,
            intervention_kinds=inference_capabilities.intervention_kinds,
            model=self.model, **forward_kwargs,
        )
        output_entries = collect_output_entries(
            self.output_controls, steered_input_ids, runtime_kwargs,
            attention_mask=steered_attention_mask, for_scoring=True, **forward_kwargs,
        )
        items = [
            ScoringItem(
                prompt=PreparedPrompt.from_token_ids(
                    steered_input_ids[i:i + 1], steered_attention_mask[i:i + 1],
                ),
                ref_output_ids=ref_output_ids[i:i + 1],
                state_entries=state_entries,
                output_entries=output_entries,
            )
            for i in range(batch_size)
        ]
        with backend.open_session() as session:
            return session.score(items, score_params)

    # sequential fallback (one or more controls do not support batching): per-item
    # preparation and entries, one scoring pass per item
    if isinstance(input_ids, list):
        input_ids = torch.tensor(input_ids, dtype=torch.long)
    if input_ids.ndim == 1:
        input_ids = input_ids.unsqueeze(0)
    input_ids = input_ids.to(device)

    if attention_mask is not None:
        if isinstance(attention_mask, list):
            attention_mask = torch.as_tensor(attention_mask, dtype=torch.long)
        if attention_mask.ndim == 1:
            attention_mask = attention_mask.unsqueeze(0)
        attention_mask = attention_mask.to(device)

    num_inputs = input_ids.size(0)
    if ref_output_ids.size(0) == 1 and num_inputs > 1:
        ref_output_ids = ref_output_ids.expand(num_inputs, -1)
    if ref_len == 0:
        return torch.zeros((num_inputs, 0), device=device, dtype=torch.float32)

    all_logprobs = []
    with backend.open_session() as session:
        for i in range(num_inputs):
            single_attention_mask = attention_mask[i:i + 1] if attention_mask is not None else None
            steered_input_ids, steered_attention_mask = prepare_inputs(
                input_ids[i:i + 1],
                single_attention_mask,
                input_controls=self.input_controls,
                tokenizer=self.tokenizer,
                device=device,
                runtime_kwargs=runtime_kwargs,
                warnings_state=self._prompt_warnings,
            )
            state_entries = collect_state_entries(
                self.state_controls, steered_input_ids, runtime_kwargs,
                attention_mask=steered_attention_mask, hooks_in_process=hooks_in_process,
                lowered_state=self._lowered_state, backend=backend,
                intervention_kinds=inference_capabilities.intervention_kinds,
                model=self.model, **forward_kwargs,
            )
            output_entries = collect_output_entries(
                self.output_controls, steered_input_ids, runtime_kwargs,
                attention_mask=steered_attention_mask, for_scoring=True, **forward_kwargs,
            )
            item = ScoringItem(
                prompt=PreparedPrompt.from_token_ids(steered_input_ids, steered_attention_mask),
                ref_output_ids=ref_output_ids[i:i + 1],
                state_entries=state_entries,
                output_entries=output_entries,
            )
            all_logprobs.append(session.score([item], score_params))
    return torch.cat(all_logprobs, dim=0)
generate(inputs=None, attention_mask=None, runtime_kwargs=None, return_output=False, *, text=None, messages=None, input_ids=None, **gen_kwargs)
generate(inputs: str, attention_mask: None = ..., runtime_kwargs: dict | None = ..., return_output: Literal[False] = ..., **gen_kwargs: Any) -> str
generate(inputs: list[str], attention_mask: None = ..., runtime_kwargs: dict | None = ..., return_output: Literal[False] = ..., **gen_kwargs: Any) -> list[str]
generate(*, text: str, runtime_kwargs: dict | None = ..., return_output: Literal[False] = ..., **gen_kwargs: Any) -> str
generate(*, text: Sequence[str], runtime_kwargs: dict | None = ..., return_output: Literal[False] = ..., **gen_kwargs: Any) -> list[str]
generate(*, messages: Sequence[Mapping], runtime_kwargs: dict | None = ..., return_output: Literal[False] = ..., **gen_kwargs: Any) -> str
generate(*, messages: Sequence[Sequence[Mapping]], runtime_kwargs: dict | None = ..., return_output: Literal[False] = ..., **gen_kwargs: Any) -> list[str]
generate(*, input_ids: torch.Tensor | list[int] | list[list[int]], attention_mask: torch.Tensor | None = ..., runtime_kwargs: dict | None = ..., return_output: Literal[False] = ..., **gen_kwargs: Any) -> torch.Tensor
generate(inputs: Any = ..., attention_mask: torch.Tensor | None = ..., runtime_kwargs: dict | None = ..., *, text: Any = ..., messages: Any = ..., input_ids: Any = ..., return_output: Literal[True], **gen_kwargs: Any) -> Output | list[Output]
generate(inputs: str | list[str] | None = ..., attention_mask: None = ..., runtime_kwargs: dict | None = ..., return_output: bool = ..., *, text: str | Sequence[str] | None = ..., messages: Sequence[Mapping] | Sequence[Sequence[Mapping]] | None = ..., **gen_kwargs: Any) -> str | list[str] | Output | list[Output]
generate(*, input_ids: torch.Tensor | list[int] | list[list[int]], attention_mask: torch.Tensor | None = ..., runtime_kwargs: dict | None = ..., return_output: bool = ..., **gen_kwargs: Any) -> torch.Tensor | Output | list[Output]

Generate with steering across text, chat, and token prompts.

The prompt source is declared by keyword, with exactly one source per call:

Source Tokenization Default return type
text= (str) plain text str
text= (Sequence[str]) batched plain text list[str]
messages= (one conversation) apply_chat_template str
messages= (batch of conversations) batched apply_chat_template list[str]
input_ids= (1-D tokens) already tokenized; passed through torch.Tensor
input_ids= (2-D tokens) already tokenized; passed through torch.Tensor

Positional str/list[str] is accepted as a convenience for text prompts and behaves like text=; any other positional shape raises TypeError. With return_output=True, the return is always Output (single) or list[Output] (batched) regardless of source. The per-source methods generate_text, generate_messages, and generate_tokens expose the same behavior with source-specific signatures and document each source's rules.

The decoded text returns carry exactly one candidate per prompt. Requesting multiple candidates (num_return_sequences or n greater than 1) with text= or messages= raises ValueError unless return_output=True, where Output.output_ids holds one row per candidate and Output.finish_reasons one reason per candidate. The token return (input_ids=) carries candidates in its shape, [batch * n, gen_len] with each prompt's candidates contiguous, matching model.generate.

Parameters:

Name Type Description Default
inputs str | list[str] | None

Positional convenience for text prompts (str or list[str]), behaving like text=. Any other positional shape raises TypeError; use the keywords below.

None
attention_mask Tensor | None

Attention mask, valid only with input_ids=.

None
runtime_kwargs dict | None

Per-generation parameters for controls (e.g., {"substrings": [...]}).

None
return_output bool

If True, return one or more Output objects instead of decoded text / token IDs.

False
text str | Sequence[str] | None

Text prompt as a str or a sequence of str.

None
messages Sequence[Mapping] | Sequence[Sequence[Mapping]] | None

Chat prompt as one conversation (a sequence of mappings) or a batch (a sequence of sequences of mappings).

None
input_ids Tensor | list[int] | list[list[int]] | None

Token prompt as a 1-D/2-D integer tensor, list[int], or list[list[int]].

None
**gen_kwargs Any

Generation parameters in model.generate vocabulary, normalized through GenerationParams and executed by the inference backend's session (unlisted keys pass through in process and raise on API backends). Two keys are reserved and consumed here rather than forwarded to the backend:

- `return_full_sequence: bool` to include the prompt in the returned token IDs.
    For a padded batch the returned rows are in left-packed layout
    (`[pads, prompt, continuation]`), the layout the continuation was
    generated from.
- `chat_template_kwargs: dict` forwarded to `apply_chat_template` after the
    pipeline-owned template kwargs. Valid only with `messages=` (pairing it with
    `text=`/`input_ids=` raises `TypeError`); it may not name any pipeline-owned
    template kwarg (`return_tensors`, `padding`, `add_generation_prompt`,
    `return_dict`, else `ValueError`). An empty mapping is a no-op. The toolkit
    does not interpret the mapping; keys are model-family specific (e.g.
    `enable_thinking`), and models whose templates expose no such switch are
    unaffected.
{}

Returns:

Type Description
str | list[str] | Tensor | Output | list[Output]

See dispatch table above.

Raises:

Type Description
RuntimeError

If steer() has not yet been called.

TypeError

If no prompt source or more than one is provided, if a source fails validation, if attention_mask is paired with text=/messages=, if chat_template_kwargs is paired with text=/input_ids=, or if chat_template_kwargs is not a mapping.

ValueError

If a token tensor is not 1-D/2-D, nested token lists are ragged, a text/ chat sequence is empty, chat_template_kwargs names a pipeline-owned template argument, or multiple candidates per prompt (num_return_sequences/n greater than 1) are requested on a decoded text return without return_output=True.

Source code in steerability/algorithms/core/steering_pipeline.py
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
def generate(
        self,
        inputs: str | list[str] | None = None,
        attention_mask: torch.Tensor | None = None,
        runtime_kwargs: dict | None = None,
        return_output: bool = False,
        *,
        text: str | Sequence[str] | None = None,
        messages: Sequence[Mapping] | Sequence[Sequence[Mapping]] | None = None,
        input_ids: torch.Tensor | list[int] | list[list[int]] | None = None,
        **gen_kwargs: Any,
) -> str | list[str] | torch.Tensor | Output | list[Output]:
    """Generate with steering across text, chat, and token prompts.

    The prompt source is declared by keyword, with exactly one source per call:

    | Source | Tokenization | Default return type |
    | --- | --- | --- |
    | `text=` (`str`) | plain text | `str` |
    | `text=` (`Sequence[str]`) | batched plain text | `list[str]` |
    | `messages=` (one conversation) | `apply_chat_template` | `str` |
    | `messages=` (batch of conversations) | batched `apply_chat_template` | `list[str]` |
    | `input_ids=` (1-D tokens) | already tokenized; passed through | `torch.Tensor` |
    | `input_ids=` (2-D tokens) | already tokenized; passed through | `torch.Tensor` |

    Positional `str`/`list[str]` is accepted as a convenience for text prompts and behaves like
    `text=`; any other positional shape raises `TypeError`. With `return_output=True`, the return
    is always `Output` (single) or `list[Output]` (batched) regardless of source. The per-source
    methods `generate_text`, `generate_messages`, and `generate_tokens` expose the same behavior
    with source-specific signatures and document each source's rules.

    The decoded text returns carry exactly one candidate per prompt. Requesting multiple
    candidates (`num_return_sequences` or `n` greater than 1) with `text=` or `messages=`
    raises `ValueError` unless `return_output=True`, where `Output.output_ids` holds one row
    per candidate and `Output.finish_reasons` one reason per candidate. The token return
    (`input_ids=`) carries candidates in its shape, `[batch * n, gen_len]` with each prompt's
    candidates contiguous, matching `model.generate`.

    Args:
        inputs: Positional convenience for text prompts (`str` or `list[str]`), behaving like
            `text=`. Any other positional shape raises `TypeError`; use the keywords below.
        attention_mask: Attention mask, valid only with `input_ids=`.
        runtime_kwargs: Per-generation parameters for controls (e.g., `{"substrings": [...]}`).
        return_output: If True, return one or more `Output` objects instead of decoded text /
            token IDs.
        text: Text prompt as a `str` or a sequence of `str`.
        messages: Chat prompt as one conversation (a sequence of mappings) or a batch (a sequence
            of sequences of mappings).
        input_ids: Token prompt as a 1-D/2-D integer tensor, `list[int]`, or `list[list[int]]`.
        **gen_kwargs: Generation parameters in `model.generate` vocabulary, normalized
            through `GenerationParams` and executed by the inference backend's session
            (unlisted keys pass through in process and raise on API backends). Two keys are
            reserved and consumed here rather than forwarded to the backend:

                - `return_full_sequence: bool` to include the prompt in the returned token IDs.
                    For a padded batch the returned rows are in left-packed layout
                    (`[pads, prompt, continuation]`), the layout the continuation was
                    generated from.
                - `chat_template_kwargs: dict` forwarded to `apply_chat_template` after the
                    pipeline-owned template kwargs. Valid only with `messages=` (pairing it with
                    `text=`/`input_ids=` raises `TypeError`); it may not name any pipeline-owned
                    template kwarg (`return_tensors`, `padding`, `add_generation_prompt`,
                    `return_dict`, else `ValueError`). An empty mapping is a no-op. The toolkit
                    does not interpret the mapping; keys are model-family specific (e.g.
                    `enable_thinking`), and models whose templates expose no such switch are
                    unaffected.

    Returns:
        See dispatch table above.

    Raises:
        RuntimeError: If `steer()` has not yet been called.
        TypeError: If no prompt source or more than one is provided, if a source fails
            validation, if `attention_mask` is paired with `text=`/`messages=`, if
            `chat_template_kwargs` is paired with `text=`/`input_ids=`, or if
            `chat_template_kwargs` is not a mapping.
        ValueError: If a token tensor is not 1-D/2-D, nested token lists are ragged, a text/
            chat sequence is empty, `chat_template_kwargs` names a pipeline-owned template
            argument, or multiple candidates per prompt (`num_return_sequences`/`n` greater
            than 1) are requested on a decoded text return without `return_output=True`.
    """
    if not self._is_steered:
        raise RuntimeError("Must call `.steer()` before `.generate()`.")

    runtime_kwargs = runtime_kwargs or {}
    return_full_sequence = bool(gen_kwargs.pop("return_full_sequence", False))
    chat_template_kwargs = gen_kwargs.pop("chat_template_kwargs", None)

    if chat_template_kwargs is not None:
        if not isinstance(chat_template_kwargs, Mapping):
            raise TypeError(
                "chat_template_kwargs must be a mapping of chat-template keyword arguments; got "
                f"{type(chat_template_kwargs).__name__}."
            )
        reserved = {"return_tensors", "padding", "add_generation_prompt", "return_dict"}
        collisions = reserved & set(chat_template_kwargs)
        if collisions:
            names = ", ".join(sorted(collisions))
            raise ValueError(
                f"chat_template_kwargs may not override pipeline-owned template arguments: {names}."
            )

    kind, payload = resolve_generate_source(inputs, text, messages, input_ids)

    # attention_mask pairing
    if attention_mask is not None and kind != "tokens":
        raise TypeError(
            "attention_mask is only valid with token input (input_ids=); it is derived "
            "automatically for text= and messages=."
        )

    # chat_template_kwargs pairing
    if chat_template_kwargs is not None and kind != "messages":
        raise TypeError(
            "chat_template_kwargs is only valid with chat input (messages=); text= and input_ids= "
            "are already templated or template-free."
        )

    # candidate-count pairing: the decoded text return carries exactly one candidate per
    # prompt, so multiple candidates require the Output return or the token return
    if kind != "tokens" and not return_output:
        requested_n = gen_kwargs.get("n", gen_kwargs.get("num_return_sequences"))
        if isinstance(requested_n, int) and requested_n > 1:
            raise ValueError(
                f"num_return_sequences={requested_n} requests multiple candidates per prompt, "
                "but the decoded text return carries exactly one candidate per prompt; pass "
                "return_output=True to receive every candidate (Output.output_ids holds one "
                "row per candidate and Output.decode() decodes them all), or generate with "
                "input_ids= for a [batch * n, gen_len] token return."
            )

    # resolve the prompt tensors per modality
    message_handled: set[int] = set()
    if kind == "text":
        prompt_input_ids, prompt_attention_mask, is_single = resolve_text_prompt(
            payload,
            input_controls=self.input_controls,
            tokenizer=self.tokenizer,
            warnings_state=self._prompt_warnings,
        )
    elif kind == "messages":
        prompt_input_ids, prompt_attention_mask, message_handled, is_single = resolve_messages_prompt(
            payload,
            runtime_kwargs,
            input_controls=self.input_controls,
            tokenizer=self.tokenizer,
            chat_template_kwargs=chat_template_kwargs,
        )
    else:  # tokens
        prompt_input_ids, prompt_attention_mask, is_single = resolve_token_prompt(
            payload,
            attention_mask,
            input_controls=self.input_controls,
            warnings_state=self._prompt_warnings,
        )

    return self._execute_generation(
        prompt_input_ids=prompt_input_ids,
        prompt_attention_mask=prompt_attention_mask,
        message_handled=message_handled,
        decode_text=(kind != "tokens"),
        is_single=is_single,
        runtime_kwargs=runtime_kwargs,
        return_output=return_output,
        return_full_sequence=return_full_sequence,
        gen_kwargs=gen_kwargs,
    )
generate_messages(messages, *, chat_template_kwargs=None, runtime_kwargs=None, return_output=False, return_full_sequence=False, **gen_kwargs)
generate_messages(messages: Sequence[Mapping], *, chat_template_kwargs: Mapping | None = ..., runtime_kwargs: dict | None = ..., return_output: Literal[False] = ..., return_full_sequence: bool = ..., **gen_kwargs: Any) -> str
generate_messages(messages: Sequence[Sequence[Mapping]], *, chat_template_kwargs: Mapping | None = ..., runtime_kwargs: dict | None = ..., return_output: Literal[False] = ..., return_full_sequence: bool = ..., **gen_kwargs: Any) -> list[str]
generate_messages(messages: Sequence[Mapping] | Sequence[Sequence[Mapping]], *, chat_template_kwargs: Mapping | None = ..., runtime_kwargs: dict | None = ..., return_output: Literal[True], return_full_sequence: bool = ..., **gen_kwargs: Any) -> Output | list[Output]
generate_messages(messages: Sequence[Mapping] | Sequence[Sequence[Mapping]], *, chat_template_kwargs: Mapping | None = ..., runtime_kwargs: dict | None = ..., return_output: bool = ..., return_full_sequence: bool = ..., **gen_kwargs: Any) -> str | list[str] | Output | list[Output]

Generate from chat prompts through the tokenizer's chat template.

One conversation (a sequence of mappings) returns str; a batch (a sequence of sequences of mappings) returns list[str] (Output or list[Output] with return_output=True). Every input control's adapt_messages runs before templating; controls whose adapt_messages returns None run their token-level adapt after tokenization, so each control applies exactly once per call. The decoded return carries exactly one candidate per prompt; num_return_sequences/n greater than 1 raises ValueError unless return_output=True.

Parameters:

Name Type Description Default
messages Sequence[Mapping] | Sequence[Sequence[Mapping]]

One conversation or a batch of conversations.

required
chat_template_kwargs Mapping | None

Extra keyword arguments forwarded to apply_chat_template after the pipeline-owned template kwargs. May not name a pipeline-owned template kwarg (return_tensors, padding, add_generation_prompt, return_dict). The toolkit does not interpret the mapping; keys are model-family specific (e.g. enable_thinking).

None
runtime_kwargs dict | None

Per-generation parameters for controls.

None
return_output bool

If True, return Output (single) or list[Output] (batched).

False
return_full_sequence bool

If True, include the prompt in the returned token IDs. Returned ids exclude the prompt by default; do not slice the result by prompt length.

False
**gen_kwargs Any

Generation parameters, as for generate().

{}

Returns:

Type Description
str | list[str] | Output | list[Output]

str, list[str], Output, or list[Output].

Source code in steerability/algorithms/core/steering_pipeline.py
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
def generate_messages(
        self,
        messages: Sequence[Mapping] | Sequence[Sequence[Mapping]],
        *,
        chat_template_kwargs: Mapping | None = None,
        runtime_kwargs: dict | None = None,
        return_output: bool = False,
        return_full_sequence: bool = False,
        **gen_kwargs: Any,
) -> str | list[str] | Output | list[Output]:
    """Generate from chat prompts through the tokenizer's chat template.

    One conversation (a sequence of mappings) returns `str`; a batch (a sequence of
    sequences of mappings) returns `list[str]` (`Output` or `list[Output]` with
    `return_output=True`). Every input control's `adapt_messages` runs before templating;
    controls whose `adapt_messages` returns None run their token-level `adapt` after
    tokenization, so each control applies exactly once per call. The decoded return
    carries exactly one candidate per prompt; `num_return_sequences`/`n` greater than 1
    raises `ValueError` unless `return_output=True`.

    Args:
        messages: One conversation or a batch of conversations.
        chat_template_kwargs: Extra keyword arguments forwarded to `apply_chat_template`
            after the pipeline-owned template kwargs. May not name a pipeline-owned
            template kwarg (`return_tensors`, `padding`, `add_generation_prompt`,
            `return_dict`). The toolkit does not interpret the mapping; keys are
            model-family specific (e.g. `enable_thinking`).
        runtime_kwargs: Per-generation parameters for controls.
        return_output: If True, return `Output` (single) or `list[Output]` (batched).
        return_full_sequence: If True, include the prompt in the returned token IDs.
            Returned ids exclude the prompt by default; do not slice the result by
            prompt length.
        **gen_kwargs: Generation parameters, as for `generate()`.

    Returns:
        `str`, `list[str]`, `Output`, or `list[Output]`.
    """
    gen_kwargs["return_full_sequence"] = return_full_sequence
    if chat_template_kwargs is not None:
        gen_kwargs["chat_template_kwargs"] = chat_template_kwargs
    return self.generate(
        messages=messages, runtime_kwargs=runtime_kwargs, return_output=return_output,
        **gen_kwargs,
    )
generate_text(text, *, runtime_kwargs=None, return_output=False, return_full_sequence=False, **gen_kwargs)
generate_text(text: str, *, runtime_kwargs: dict | None = ..., return_output: Literal[False] = ..., return_full_sequence: bool = ..., **gen_kwargs: Any) -> str
generate_text(text: Sequence[str], *, runtime_kwargs: dict | None = ..., return_output: Literal[False] = ..., return_full_sequence: bool = ..., **gen_kwargs: Any) -> list[str]
generate_text(text: str | Sequence[str], *, runtime_kwargs: dict | None = ..., return_output: Literal[True], return_full_sequence: bool = ..., **gen_kwargs: Any) -> Output | list[Output]
generate_text(text: str | Sequence[str], *, runtime_kwargs: dict | None = ..., return_output: bool = ..., return_full_sequence: bool = ..., **gen_kwargs: Any) -> str | list[str] | Output | list[Output]

Generate from plain-text prompts.

A str returns str; a sequence of str returns list[str] (Output or list[Output] with return_output=True). Input controls apply at token level only; adapt_messages does not fire on text input. The decoded return carries exactly one candidate per prompt; num_return_sequences/n greater than 1 raises ValueError unless return_output=True.

Parameters:

Name Type Description Default
text str | Sequence[str]

Text prompt as a str or a sequence of str.

required
runtime_kwargs dict | None

Per-generation parameters for controls.

None
return_output bool

If True, return Output (single) or list[Output] (batched).

False
return_full_sequence bool

If True, include the prompt in the returned token IDs. Returned ids exclude the prompt by default; do not slice the result by prompt length.

False
**gen_kwargs Any

Generation parameters, as for generate().

{}

Returns:

Type Description
str | list[str] | Output | list[Output]

str, list[str], Output, or list[Output].

Source code in steerability/algorithms/core/steering_pipeline.py
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
def generate_text(
        self,
        text: str | Sequence[str],
        *,
        runtime_kwargs: dict | None = None,
        return_output: bool = False,
        return_full_sequence: bool = False,
        **gen_kwargs: Any,
) -> str | list[str] | Output | list[Output]:
    """Generate from plain-text prompts.

    A `str` returns `str`; a sequence of `str` returns `list[str]` (`Output` or
    `list[Output]` with `return_output=True`). Input controls apply at token level only;
    `adapt_messages` does not fire on text input. The decoded return carries exactly one
    candidate per prompt; `num_return_sequences`/`n` greater than 1 raises `ValueError`
    unless `return_output=True`.

    Args:
        text: Text prompt as a `str` or a sequence of `str`.
        runtime_kwargs: Per-generation parameters for controls.
        return_output: If True, return `Output` (single) or `list[Output]` (batched).
        return_full_sequence: If True, include the prompt in the returned token IDs.
            Returned ids exclude the prompt by default; do not slice the result by
            prompt length.
        **gen_kwargs: Generation parameters, as for `generate()`.

    Returns:
        `str`, `list[str]`, `Output`, or `list[Output]`.
    """
    gen_kwargs["return_full_sequence"] = return_full_sequence
    return self.generate(
        text=text, runtime_kwargs=runtime_kwargs, return_output=return_output, **gen_kwargs,
    )
generate_tokens(input_ids, attention_mask=None, *, runtime_kwargs=None, return_output=False, return_full_sequence=False, **gen_kwargs)
generate_tokens(input_ids: torch.Tensor | list[int] | list[list[int]], attention_mask: torch.Tensor | None = ..., *, runtime_kwargs: dict | None = ..., return_output: Literal[False] = ..., return_full_sequence: bool = ..., **gen_kwargs: Any) -> torch.Tensor
generate_tokens(input_ids: torch.Tensor | list[int] | list[list[int]], attention_mask: torch.Tensor | None = ..., *, runtime_kwargs: dict | None = ..., return_output: Literal[True], return_full_sequence: bool = ..., **gen_kwargs: Any) -> Output | list[Output]
generate_tokens(input_ids: torch.Tensor | list[int] | list[list[int]], attention_mask: torch.Tensor | None = ..., *, runtime_kwargs: dict | None = ..., return_output: bool = ..., return_full_sequence: bool = ..., **gen_kwargs: Any) -> torch.Tensor | Output | list[Output]

Generate from already-tokenized prompts.

Returns a torch.Tensor of continuation ids (Output or list[Output] with return_output=True). Input controls apply at token level only; adapt_messages does not fire on token input. With num_return_sequences/n greater than 1 the returned tensor is [batch * n, gen_len] with each prompt's candidates contiguous, matching model.generate.

Parameters:

Name Type Description Default
input_ids Tensor | list[int] | list[list[int]]

Token prompt as a 1-D/2-D integer tensor, list[int], or list[list[int]].

required
attention_mask Tensor | None

Attention mask matching input_ids, or None to derive it.

None
runtime_kwargs dict | None

Per-generation parameters for controls.

None
return_output bool

If True, return Output (single) or list[Output] (batched).

False
return_full_sequence bool

If True, include the prompt in the returned token IDs. Returned ids exclude the prompt by default; do not slice the result by prompt length.

False
**gen_kwargs Any

Generation parameters, as for generate().

{}

Returns:

Type Description
Tensor | Output | list[Output]

torch.Tensor, Output, or list[Output].

Source code in steerability/algorithms/core/steering_pipeline.py
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
def generate_tokens(
        self,
        input_ids: torch.Tensor | list[int] | list[list[int]],
        attention_mask: torch.Tensor | None = None,
        *,
        runtime_kwargs: dict | None = None,
        return_output: bool = False,
        return_full_sequence: bool = False,
        **gen_kwargs: Any,
) -> torch.Tensor | Output | list[Output]:
    """Generate from already-tokenized prompts.

    Returns a `torch.Tensor` of continuation ids (`Output` or `list[Output]` with
    `return_output=True`). Input controls apply at token level only; `adapt_messages`
    does not fire on token input. With `num_return_sequences`/`n` greater than 1 the
    returned tensor is `[batch * n, gen_len]` with each prompt's candidates contiguous,
    matching `model.generate`.

    Args:
        input_ids: Token prompt as a 1-D/2-D integer tensor, `list[int]`, or
            `list[list[int]]`.
        attention_mask: Attention mask matching `input_ids`, or None to derive it.
        runtime_kwargs: Per-generation parameters for controls.
        return_output: If True, return `Output` (single) or `list[Output]` (batched).
        return_full_sequence: If True, include the prompt in the returned token IDs.
            Returned ids exclude the prompt by default; do not slice the result by
            prompt length.
        **gen_kwargs: Generation parameters, as for `generate()`.

    Returns:
        `torch.Tensor`, `Output`, or `list[Output]`.
    """
    gen_kwargs["return_full_sequence"] = return_full_sequence
    return self.generate(
        input_ids=input_ids, attention_mask=attention_mask, runtime_kwargs=runtime_kwargs,
        return_output=return_output, **gen_kwargs,
    )
release_backends()

Release every backend this pipeline constructed and empty the cache.

Subsequent operations construct fresh backends against the same specs. Lowered intervention entries and staged artifacts persist, so a released pipeline remains usable at the cost of re-booting engines on next use. Release is idempotent. Engine-owning backends shut down deterministically.

Source code in steerability/algorithms/core/steering_pipeline.py
405
406
407
408
409
410
411
412
413
414
415
416
417
418
def release_backends(self) -> None:
    """Release every backend this pipeline constructed and empty the cache.

    Subsequent operations construct fresh backends against the same specs. Lowered
    intervention entries and staged artifacts persist, so a released pipeline remains usable
    at the cost of re-booting engines on next use. Release is idempotent. Engine-owning
    backends shut down deterministically.
    """
    backends, self._backends = self._backends, {}
    for backend in backends.values():
        try:
            backend.release()
        except Exception:
            logger.warning("Backend release failed", exc_info=True)
steer(**steer_kwargs)

Apply all steering controls per the steer plan.

Executes each control's steer() method in a fixed bottom-up order: structural -> input -> state -> output, and in list order within each category. If any control's steer() method returns a PreTrainedModel instance, it replaces the current model for subsequent controls, so structural controls thread the model through in list order.

Before any control runs, check() evaluates the configured backend and raises on any generate-phase failure. Each control's steer() receives session=, a session scoped to its declared steer_access(), unless the caller supplied its own session keyword, and receives the live model only at ModelAccess.MODULE. On the Hugging Face backend every step runs against the live model in one phase. On engine backends the plan's stage-venued steps run first on a temporary in-process model that is freed before the engine boots (exported artifacts are the handoff), then the session-venued steps run through the engine session. The only channel between one control's steer and another's is the pipeline model, and every control that can touch it runs in the stage phase, so per-phase global order preserves the composition semantics of the single-phase order.

A failed steer releases any backends it constructed before re-raising, so it does not leave an engine behind and a retried steer re-boots. A repeated call on an already-steered pipeline is a no-op.

Warns:

Type Description
UserWarning

If two or more enabled controls declare the same RUNTIME_KWARGS_SCHEMA variable name, if a calibrated fit is fitted in process while its artifact is read on an engine, or if engine capture fails the steer-time smoke test and fitting degrades to a staged in-process model.

Raises:

Type Description
RuntimeError

If no model is available after steering, or the staged in-process model was retained past the steer stage.

ValueError

If an enabled control's RUNTIME_KWARGS_SCHEMA entry declares an invalid scope, or two enabled controls declare one runtime kwarg with a different scope or type.

UnsupportedPipelineError

If any enabled control is unsupported at the generate phase on the configured backend.

ModuleNotFoundError

If a configured backend kind requires an optional dependency that is not installed (e.g. the vllm extra).

Source code in steerability/algorithms/core/steering_pipeline.py
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
def steer(self, **steer_kwargs) -> None:
    """Apply all steering controls per the steer plan.

    Executes each control's steer() method in a fixed bottom-up order: structural -> input -> state -> output,
    and in list order within each category. If any control's steer() method returns a
    PreTrainedModel instance, it replaces the current model for subsequent controls, so
    structural controls thread the model through in list order.

    Before any control runs, `check()` evaluates the configured backend and raises on any
    generate-phase failure. Each control's `steer()` receives `session=`, a session scoped
    to its declared `steer_access()`, unless the caller supplied its own `session` keyword,
    and receives the live model only at `ModelAccess.MODULE`. On the Hugging Face backend
    every step runs against the live model in one phase. On engine backends the plan's
    stage-venued steps run first on a temporary in-process model that is freed before the
    engine boots (exported artifacts are the handoff), then the session-venued steps run
    through the engine session. The only channel between one control's steer and another's
    is the pipeline model, and every control that can touch it runs in the stage phase, so
    per-phase global order preserves the composition semantics of the single-phase order.

    A failed steer releases any backends it constructed before re-raising, so it does not
    leave an engine behind and a retried steer re-boots. A repeated call on an
    already-steered pipeline is a no-op.

    Warns:
        UserWarning: If two or more enabled controls declare the same `RUNTIME_KWARGS_SCHEMA`
            variable name, if a calibrated fit is fitted in process while its artifact is
            read on an engine, or if engine capture fails the steer-time smoke test and
            fitting degrades to a staged in-process model.

    Raises:
        RuntimeError: If no model is available after steering, or the staged in-process
            model was retained past the steer stage.
        ValueError: If an enabled control's `RUNTIME_KWARGS_SCHEMA` entry declares an invalid
            `scope`, or two enabled controls declare one runtime kwarg with a different
            `scope` or `type`.
        UnsupportedPipelineError: If any enabled control is unsupported at the generate
            phase on the configured backend.
        ModuleNotFoundError: If a configured backend kind requires an optional dependency
            that is not installed (e.g. the `vllm` extra).
    """
    if self._is_steered:
        return

    try:
        self._warn_on_runtime_kwargs_overlap()

        spec = self._resolve_backend_spec(self.backend)
        report = self.check()
        report.raise_for("generate")
        self._support_report = report

        if spec.kind == "huggingface":
            self._steer_in_process(spec, report.plan, steer_kwargs)
        else:
            self._resolve_client_tokenizer(spec)
            self._steer_on_engine(spec, report.plan, steer_kwargs)

        if self.tokenizer is None:
            repo = getattr(self.model, "name_or_path", None)
            source = repo or self._structural_out_path()
            if source is None:
                raise RuntimeError("Failed to resolve tokenizer post‑steer.")
            try:
                self.tokenizer = AutoTokenizer.from_pretrained(
                    source,
                    trust_remote_code=self.trust_remote_code,
                )
                self.tokenizer = ensure_pad_token(self.tokenizer)

            except Exception as exception:
                raise RuntimeError("Failed to resolve tokenizer post‑steer.") from exception

        self._inject_tokenizer()

        # a spec-consuming backend gets every enabled control's interventions lowered now,
        # so inexpressible configurations fail before the first generate and artifacts are
        # staged once
        self._lowered_state = lower_state_controls(
            self.state_controls, self._backend_for(spec), capabilities_for_spec(spec),
        )
    except Exception:
        self.release_backends()
        raise

    # return steered pipeline
    self._is_steered = True
to_spipe(*, freeze=None, model_ref=None)

Serialize this pipeline as an SPipe.

A steered pipeline freezes by default: each enabled control's steer-time products are exported into a content-addressed artifact store and its resolved constructor form is recorded alongside the recipe, so the loaded pipeline steers cheaply and model-free. An unsteered pipeline yields a recipe-only spipe; freeze=False forces recipe-only from a steered pipeline.

Parameters:

Name Type Description Default
freeze bool | None

Freeze the resolution. Defaults to the pipeline's steered state.

None
model_ref str | None

Explicit model reference recorded in the spipe, overriding model_name_or_path and the loaded model's name_or_path.

None

Returns:

Type Description
SPipe

The built SPipe (call its save() to write a .spipe file or directory).

Raises:

Type Description
SpipeSaveError

If no model reference is resolvable, a control is unregistered or cannot serialize, or a control cannot freeze.

Source code in steerability/algorithms/core/steering_pipeline.py
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
def to_spipe(self, *, freeze: bool | None = None, model_ref: str | None = None) -> "SPipe":
    """Serialize this pipeline as an `SPipe`.

    A steered pipeline freezes by default: each enabled control's steer-time products are
    exported into a content-addressed artifact store and its resolved constructor form is
    recorded alongside the recipe, so the loaded pipeline steers cheaply and model-free.
    An unsteered pipeline yields a recipe-only spipe; `freeze=False` forces recipe-only
    from a steered pipeline.

    Args:
        freeze: Freeze the resolution. Defaults to the pipeline's steered state.
        model_ref: Explicit model reference recorded in the spipe, overriding
            `model_name_or_path` and the loaded model's `name_or_path`.

    Returns:
        The built `SPipe` (call its `save()` to write a `.spipe` file or directory).

    Raises:
        SpipeSaveError: If no model reference is resolvable, a control is unregistered or
            cannot serialize, or a control cannot freeze.
    """
    from steerability.spipe.freeze import build_spipe

    return build_spipe(self, freeze=freeze, model_ref=model_ref)

sweeps

Configuration sweeps over one base model: expansion, pre-flight support checks, and pipeline lifecycle.

One configuration is one concrete list of control instances. expand_configurations enumerates the configurations of a pipelines mapping (fixed controls, ControlSpec sweeps, and the empty baseline) as ConfigPoints carrying canonical identity; preflight evaluates backend support per point before any model or engine work; PipelineFactory builds, steers, and releases one pipeline per point with a shared preloaded base model on the Hugging Face backend and a fingerprint tripwire over it.

logger = logging.getLogger(__name__) module-attribute

ConfigPoint dataclass

One concrete configuration of one named pipeline.

Attributes:

Name Type Description
pipeline_name str

Name of the pipeline the point belongs to.

config_id str

Canonical configuration identifier; "baseline" for the empty pipeline, else the digest of descriptor.

descriptor Mapping[str, Any]

JSON-serializable canonical descriptor of the configuration (control classes and their full constructor parameters).

specs tuple | None

The ControlSpec list for spec-defined pipelines, else None.

params Mapping[str, Mapping[str, Any]] | None

Mapping from resolved spec name to that spec's resolved constructor kwargs, else None for fixed and baseline pipelines.

controls_factory Callable[[], list]

Zero-argument callable building the configuration's control instances. Fixed pipelines return the user-supplied instances on every call; spec pipelines instantiate fresh controls per call, so pre-flight instances are discarded and execution re-instantiates.

Source code in steerability/algorithms/core/sweeps.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
@dataclass(frozen=True, slots=True)
class ConfigPoint:
    """One concrete configuration of one named pipeline.

    Attributes:
        pipeline_name: Name of the pipeline the point belongs to.
        config_id: Canonical configuration identifier; `"baseline"` for the empty pipeline, else
            the digest of `descriptor`.
        descriptor: JSON-serializable canonical descriptor of the configuration (control classes
            and their full constructor parameters).
        specs: The `ControlSpec` list for spec-defined pipelines, else None.
        params: Mapping from resolved spec name to that spec's resolved constructor kwargs, else
            None for fixed and baseline pipelines.
        controls_factory: Zero-argument callable building the configuration's control instances.
            Fixed pipelines return the user-supplied instances on every call; spec pipelines
            instantiate fresh controls per call, so pre-flight instances are discarded and
            execution re-instantiates.
    """

    pipeline_name: str
    config_id: str
    descriptor: Mapping[str, Any]
    specs: tuple | None
    params: Mapping[str, Mapping[str, Any]] | None
    controls_factory: Callable[[], list]
config_id instance-attribute
controls_factory instance-attribute
descriptor instance-attribute
params instance-attribute
pipeline_name instance-attribute
specs instance-attribute

PipelineFactory

Build, steer, and release one SteeringPipeline per configuration against one base model.

On the Hugging Face backend, configurations without an enabled structural control share one preloaded base model and tokenizer, loaded lazily on first use. Configurations with an enabled structural control, and every configuration on an engine backend, construct from base_model_name_or_path with the placement knobs; before such a configuration the factory drops any resident shared base, so one full model is resident at a time, and the next shared-base configuration reloads it.

The shared base is expected not to be mutated by a non-structural configuration. After each shared-base configuration a fingerprint tripwire checks the shared model for change and, on detecting one, warns naming the configuration's controls and drops the shared model so the next configuration reloads a clean base. The fingerprint samples a bounded subset of parameters, so the tripwire makes the no-mutation invariant observable rather than proven.

Parameters:

Name Type Description Default
base_model_name_or_path str | Path

Hugging Face model ID or local path of the base model.

required
backend BackendSpec | str | None

Backend forwarded to each pipeline (a BackendSpec or a known kind name); None uses the in-process Hugging Face backend.

None
fit Literal['auto', 'in_process']

Fit venue policy forwarded to each pipeline.

'auto'
hf_model_kwargs dict | None

Extra kwargs forwarded to AutoModelForCausalLM.from_pretrained on in-process loads (the shared base and each engine arm's staged steer model).

None
device_map str | dict | None

Device placement strategy for in-process loads.

'auto'
trust_remote_code bool

Trust remote code when loading tokenizers; forwarded to each pipeline.

False
Source code in steerability/algorithms/core/sweeps.py
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
class PipelineFactory:
    """Build, steer, and release one `SteeringPipeline` per configuration against one base model.

    On the Hugging Face backend, configurations without an enabled structural control share one
    preloaded base model and tokenizer, loaded lazily on first use. Configurations with an enabled
    structural control, and every configuration on an engine backend, construct from
    `base_model_name_or_path` with the placement knobs; before such a configuration the factory
    drops any resident shared base, so one full model is resident at a time, and the next
    shared-base configuration reloads it.

    The shared base is expected not to be mutated by a non-structural configuration. After each
    shared-base configuration a fingerprint tripwire checks the shared model for change and, on
    detecting one, warns naming the configuration's controls and drops the shared model so the next
    configuration reloads a clean base. The fingerprint samples a bounded subset of parameters, so
    the tripwire makes the no-mutation invariant observable rather than proven.

    Args:
        base_model_name_or_path: Hugging Face model ID or local path of the base model.
        backend: Backend forwarded to each pipeline (a `BackendSpec` or a known kind name); None
            uses the in-process Hugging Face backend.
        fit: Fit venue policy forwarded to each pipeline.
        hf_model_kwargs: Extra kwargs forwarded to `AutoModelForCausalLM.from_pretrained` on
            in-process loads (the shared base and each engine arm's staged steer model).
        device_map: Device placement strategy for in-process loads.
        trust_remote_code: Trust remote code when loading tokenizers; forwarded to each pipeline.
    """

    def __init__(
        self,
        base_model_name_or_path: str | Path,
        *,
        backend: BackendSpec | str | None = None,
        fit: Literal["auto", "in_process"] = "auto",
        hf_model_kwargs: dict | None = None,
        device_map: str | dict | None = "auto",
        trust_remote_code: bool = False,
    ) -> None:
        self.base_model_name_or_path = base_model_name_or_path
        self.backend = backend
        self.fit = fit
        self.hf_model_kwargs = hf_model_kwargs or {}
        self.device_map = device_map
        self.trust_remote_code = trust_remote_code

        self._base_model: PreTrainedModel | None = None
        self._base_tokenizer: PreTrainedTokenizerBase | None = None
        self._base_fingerprint: str | None = None

    @property
    def backend_kind(self) -> str:
        """The configured backend kind (`"huggingface"`, `"vllm"`, or `"vllm-serve"`)."""
        if isinstance(self.backend, BackendSpec):
            return self.backend.kind
        return self.backend or "huggingface"

    @property
    def shared_base_fingerprint(self) -> str | None:
        """Fingerprint of the resident shared base model, or None when none is resident."""
        return self._base_fingerprint

    def _ensure_base_model(self) -> None:
        """Load the shared base model and tokenizer once (for reuse across configurations)."""
        if self._base_model is not None and self._base_tokenizer is not None:
            return
        self._base_model = AutoModelForCausalLM.from_pretrained(
            self.base_model_name_or_path,
            device_map=self.device_map,
            **self.hf_model_kwargs,
        )
        self._base_tokenizer = ensure_pad_token(AutoTokenizer.from_pretrained(
            self.base_model_name_or_path, trust_remote_code=self.trust_remote_code,
        ))
        self._base_fingerprint = self._fingerprint_or_none(self._base_model)

    def _fingerprint_or_none(self, model) -> str | None:
        """Digest of the shared base model, or None (guard disabled) when fingerprinting fails."""
        if model is None:
            return None
        try:
            return model_fingerprint(model)
        except Exception:
            logger.debug("Model fingerprint unavailable; shared-model guard disabled.", exc_info=True)
            return None

    def _drop_shared_base(self) -> None:
        """Release the shared base model and tokenizer references and reclaim memory."""
        if self._base_model is None and self._base_tokenizer is None:
            return
        self._base_model = None
        self._base_tokenizer = None
        self._base_fingerprint = None
        gc.collect()
        if torch.cuda.is_available():
            torch.cuda.empty_cache()

    def _verify_shared_base_model(self, controls: Sequence[Any]) -> None:
        """Tripwire: detect shared-base mutation after a configuration, then quarantine.

        The fingerprint samples up to 8 parameters times 64 elements, so this makes the no-mutation
        invariant observable, not proven. Warn-and-quarantine (not raise) is deliberate, since
        aborting a long sweep for one misbehaving control is worse than reloading and flagging.

        Args:
            controls: The configuration's controls, named in the warning (or "baseline" when empty).
        """
        if self._base_model is None or self._base_fingerprint is None:
            return
        current = self._fingerprint_or_none(self._base_model)
        if current == self._base_fingerprint:
            return
        names = ", ".join(type(control).__name__ for control in controls) or "baseline"
        logger.warning(
            "Shared base model changed during configuration [%s] (fingerprint %s -> %s); its recorded "
            "results reflect the mutated weights. Dropping the shared model so the next configuration "
            "reloads a clean base.",
            names, self._base_fingerprint, current,
        )
        self._drop_shared_base()

    @contextmanager
    def steered(self, controls: Sequence) -> Iterator[SteeringPipeline]:
        """Build and steer a pipeline for one configuration, releasing it on exit.

        Everything the caller does inside the `with` block runs inside the protected region: on
        exit (including on error) every control's `cleanup()` runs best effort, the pipeline's
        backends are released, the shared-base fingerprint tripwire runs for shared-base
        configurations, and memory is reclaimed.

        Args:
            controls: Instantiated controls for this configuration (empty for the baseline).

        Yields:
            The steered `SteeringPipeline`.
        """
        controls = list(controls)
        uses_shared_base = (
            self.backend_kind == "huggingface" and not _has_structural_control(controls)
        )
        common: dict[str, Any] = {"controls": controls, "backend": self.backend, "fit": self.fit}
        pipeline: SteeringPipeline | None = None
        try:
            if uses_shared_base:
                self._ensure_base_model()
                pipeline = SteeringPipeline(
                    model=self._base_model, tokenizer=self._base_tokenizer, **common,
                )
            else:
                self._drop_shared_base()
                pipeline = SteeringPipeline(
                    model_name_or_path=self.base_model_name_or_path,
                    device_map=self.device_map,
                    hf_model_kwargs=self.hf_model_kwargs,
                    trust_remote_code=self.trust_remote_code,
                    **common,
                )
            pipeline.steer()
            yield pipeline
        finally:
            if pipeline is not None:
                for control in (*pipeline.structural_controls, *pipeline.input_controls,
                                *pipeline.state_controls, *pipeline.output_controls):
                    cleanup_fn = getattr(control, "cleanup", None)
                    if callable(cleanup_fn):
                        try:
                            cleanup_fn()
                        except Exception:
                            logger.warning("Control cleanup failed", exc_info=True)
                pipeline.release_backends()
                del pipeline
            if uses_shared_base:
                self._verify_shared_base_model(controls)
            gc.collect()
            if torch.cuda.is_available():
                torch.cuda.empty_cache()

    def release(self) -> None:
        """Drop the shared base model; the factory remains usable and reloads it on next use."""
        self._drop_shared_base()
backend = backend instance-attribute
backend_kind property

The configured backend kind ("huggingface", "vllm", or "vllm-serve").

base_model_name_or_path = base_model_name_or_path instance-attribute
device_map = device_map instance-attribute
fit = fit instance-attribute
hf_model_kwargs = hf_model_kwargs or {} instance-attribute
shared_base_fingerprint property

Fingerprint of the resident shared base model, or None when none is resident.

trust_remote_code = trust_remote_code instance-attribute
release()

Drop the shared base model; the factory remains usable and reloads it on next use.

Source code in steerability/algorithms/core/sweeps.py
390
391
392
def release(self) -> None:
    """Drop the shared base model; the factory remains usable and reloads it on next use."""
    self._drop_shared_base()
steered(controls)

Build and steer a pipeline for one configuration, releasing it on exit.

Everything the caller does inside the with block runs inside the protected region: on exit (including on error) every control's cleanup() runs best effort, the pipeline's backends are released, the shared-base fingerprint tripwire runs for shared-base configurations, and memory is reclaimed.

Parameters:

Name Type Description Default
controls Sequence

Instantiated controls for this configuration (empty for the baseline).

required

Yields:

Type Description
SteeringPipeline

The steered SteeringPipeline.

Source code in steerability/algorithms/core/sweeps.py
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
@contextmanager
def steered(self, controls: Sequence) -> Iterator[SteeringPipeline]:
    """Build and steer a pipeline for one configuration, releasing it on exit.

    Everything the caller does inside the `with` block runs inside the protected region: on
    exit (including on error) every control's `cleanup()` runs best effort, the pipeline's
    backends are released, the shared-base fingerprint tripwire runs for shared-base
    configurations, and memory is reclaimed.

    Args:
        controls: Instantiated controls for this configuration (empty for the baseline).

    Yields:
        The steered `SteeringPipeline`.
    """
    controls = list(controls)
    uses_shared_base = (
        self.backend_kind == "huggingface" and not _has_structural_control(controls)
    )
    common: dict[str, Any] = {"controls": controls, "backend": self.backend, "fit": self.fit}
    pipeline: SteeringPipeline | None = None
    try:
        if uses_shared_base:
            self._ensure_base_model()
            pipeline = SteeringPipeline(
                model=self._base_model, tokenizer=self._base_tokenizer, **common,
            )
        else:
            self._drop_shared_base()
            pipeline = SteeringPipeline(
                model_name_or_path=self.base_model_name_or_path,
                device_map=self.device_map,
                hf_model_kwargs=self.hf_model_kwargs,
                trust_remote_code=self.trust_remote_code,
                **common,
            )
        pipeline.steer()
        yield pipeline
    finally:
        if pipeline is not None:
            for control in (*pipeline.structural_controls, *pipeline.input_controls,
                            *pipeline.state_controls, *pipeline.output_controls):
                cleanup_fn = getattr(control, "cleanup", None)
                if callable(cleanup_fn):
                    try:
                        cleanup_fn()
                    except Exception:
                        logger.warning("Control cleanup failed", exc_info=True)
            pipeline.release_backends()
            del pipeline
        if uses_shared_base:
            self._verify_shared_base_model(controls)
        gc.collect()
        if torch.cuda.is_available():
            torch.cuda.empty_cache()

expand_configurations(pipelines, *, base_model_name_or_path)

Enumerate the concrete configurations of a pipelines mapping, in execution order.

Each pipeline value is an empty sequence (the unsteered baseline), a list of instantiated controls (one fixed configuration), or a list of ControlSpecs (one configuration per point of the cartesian product of the specs' search spaces). Spec search spaces receive a context dict with "pipeline_name", "base_model_name_or_path", and, at resolution time, "combo_id".

Parameters:

Name Type Description Default
pipelines Mapping[str, Sequence]

Mapping from pipeline name to [], [Control, ...], or [ControlSpec, ...] (None is treated as the baseline).

required
base_model_name_or_path str | Path

The base model reference, forwarded into spec contexts.

required

Yields:

Type Description
ConfigPoint

One ConfigPoint per concrete configuration.

Raises:

Type Description
TypeError

If a pipeline mixes ControlSpec and fixed controls.

ValueError

If two ControlSpecs in one pipeline resolve to the same name.

Source code in steerability/algorithms/core/sweeps.py
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
def expand_configurations(
    pipelines: Mapping[str, Sequence],
    *,
    base_model_name_or_path: str | Path,
) -> Iterator[ConfigPoint]:
    """Enumerate the concrete configurations of a pipelines mapping, in execution order.

    Each pipeline value is an empty sequence (the unsteered baseline), a list of instantiated
    controls (one fixed configuration), or a list of `ControlSpec`s (one configuration per point
    of the cartesian product of the specs' search spaces). Spec search spaces receive a context
    dict with `"pipeline_name"`, `"base_model_name_or_path"`, and, at resolution time,
    `"combo_id"`.

    Args:
        pipelines: Mapping from pipeline name to `[]`, `[Control, ...]`, or `[ControlSpec, ...]`
            (None is treated as the baseline).
        base_model_name_or_path: The base model reference, forwarded into spec contexts.

    Yields:
        One `ConfigPoint` per concrete configuration.

    Raises:
        TypeError: If a pipeline mixes `ControlSpec` and fixed controls.
        ValueError: If two `ControlSpec`s in one pipeline resolve to the same name.
    """
    for pipeline_name, pipeline in pipelines.items():
        pipeline = list(pipeline or [])
        has_specs = any(isinstance(control, ControlSpec) for control in pipeline)
        if has_specs and not all(isinstance(control, ControlSpec) for control in pipeline):
            raise TypeError(
                f"Pipeline '{pipeline_name}' mixes ControlSpec and fixed controls. Either use only fixed controls "
                "or only ControlSpecs. Wrap fixed configs in ControlSpec(vars=None) if needed."
            )
        if not pipeline:
            yield ConfigPoint(
                pipeline_name=pipeline_name,
                config_id="baseline",
                descriptor={"controls": []},
                specs=None,
                params=None,
                controls_factory=lambda: [],
            )
            continue
        if not has_specs:
            fixed = list(pipeline)
            descriptor = config_descriptor_from_controls(fixed)
            yield ConfigPoint(
                pipeline_name=pipeline_name,
                config_id=config_digest(descriptor),
                descriptor=descriptor,
                specs=None,
                params=None,
                controls_factory=lambda fixed=fixed: fixed,
            )
            continue

        resolved_names = [spec.name or spec.control_cls.__name__ for spec in pipeline]
        duplicates = sorted({name for name in resolved_names if resolved_names.count(name) > 1})
        if duplicates:
            raise ValueError(
                f"Pipeline '{pipeline_name}' has multiple ControlSpecs resolving to the same name(s): "
                f"{duplicates}. Give each spec a distinct `name=` so their parameters are tracked separately."
            )

        base_context = {
            "pipeline_name": pipeline_name,
            "base_model_name_or_path": base_model_name_or_path,
        }
        spec_points = []
        for spec in pipeline:
            points = list(spec.iter_points(base_context)) or [{}]
            spec_points.append((spec, points))
        spec_list, points_lists = zip(*spec_points)

        for combo_id, combo in enumerate(itertools.product(*points_lists)):
            context = {**base_context, "combo_id": combo_id}
            params = {
                (spec.name or spec.control_cls.__name__): spec.resolve_params(chosen=point, context=context)
                for spec, point in zip(spec_list, combo)
            }

            def controls_factory(params=params, spec_list=spec_list):
                return [
                    spec.control_cls(**params[spec.name or spec.control_cls.__name__])
                    for spec in spec_list
                ]

            descriptor = config_descriptor_from_specs(spec_list, params)
            yield ConfigPoint(
                pipeline_name=pipeline_name,
                config_id=config_digest(descriptor),
                descriptor=descriptor,
                specs=tuple(spec_list),
                params=params,
                controls_factory=controls_factory,
            )

preflight(points, *, base_model_name_or_path, backend, fit)

Evaluate backend support for every point before any model or engine work.

Constructs one probe SteeringPipeline per point (construction performs no I/O), evaluates check(), and discards the probe. The empty baseline is trivially supported and produces no probe. Callers choose whether to raise on failures or skip the failing points.

Parameters:

Name Type Description Default
points Iterable[ConfigPoint]

The configuration points to check.

required
base_model_name_or_path str | Path

The base model reference for the probe pipelines.

required
backend BackendSpec | str | None

Backend forwarded to the probe pipelines.

required
fit Literal['auto', 'in_process']

Fit venue policy forwarded to the probe pipelines.

required

Returns:

Type Description
list[str]

One message per unsupported (point, control, phase), each naming the pipeline and its

list[str]

config_id and ending in core's stable verdict text. Empty when every point is supported.

Raises:

Type Description
ModuleNotFoundError

If a configured backend kind requires an optional dependency that is not installed.

Source code in steerability/algorithms/core/sweeps.py
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
def preflight(
    points: Iterable[ConfigPoint],
    *,
    base_model_name_or_path: str | Path,
    backend: BackendSpec | str | None,
    fit: Literal["auto", "in_process"],
) -> list[str]:
    """Evaluate backend support for every point before any model or engine work.

    Constructs one probe `SteeringPipeline` per point (construction performs no I/O), evaluates
    `check()`, and discards the probe. The empty baseline is trivially supported and produces no
    probe. Callers choose whether to raise on failures or skip the failing points.

    Args:
        points: The configuration points to check.
        base_model_name_or_path: The base model reference for the probe pipelines.
        backend: Backend forwarded to the probe pipelines.
        fit: Fit venue policy forwarded to the probe pipelines.

    Returns:
        One message per unsupported (point, control, phase), each naming the pipeline and its
        `config_id` and ending in core's stable verdict text. Empty when every point is supported.

    Raises:
        ModuleNotFoundError: If a configured backend kind requires an optional dependency that is
            not installed.
    """
    messages: list[str] = []
    for point in points:
        controls = point.controls_factory()
        if not controls:
            continue
        probe = SteeringPipeline(
            model_name_or_path=base_model_name_or_path, controls=controls,
            backend=backend, fit=fit,
        )
        report = probe.check()
        if report.ok:
            continue
        for failure in report.failures:
            messages.append(
                f"{point.pipeline_name} [{point.config_id}] {failure.control} ({failure.phase}): "
                f"{failure.message}"
            )
    return messages

utils

Utilities supporting the core steering pipeline.

assembly

Per-call payload assembly for SteeringPipeline.

Builds the entry payloads a session executes: state-control entries (per-generation hooks in process, lowered intervention specs on spec-consuming backends), output-control entries (processor and criteria stacks, lowered generation parameters, declarative constraints, engine-hosted processor specs), and the scoring-time processor application. Functions receive the pipeline's control lists and per-call tensors explicitly and hold no pipeline state.

logger = logging.getLogger(__name__) module-attribute
apply_scoring_processors(output_controls, logits, steered_input_ids, ref_output_ids, runtime_kwargs, attention_mask, is_encoder_decoder, **forward_kwargs)

Apply scoring-time logits processors position-by-position (teacher forcing).

Processors receive the same (prefix_ids, scores) view as during generation. For causal models the prefix is input ++ ref[:t] when scoring ref[t]; for encoder-decoder models the prefix is the decoder ids ref[:t+1] when scoring ref[t+1] (matching the existing target alignment in both paths).

Source code in steerability/algorithms/core/utils/assembly.py
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
def apply_scoring_processors(
    output_controls: Sequence[OutputControl],
    logits,
    steered_input_ids,
    ref_output_ids,
    runtime_kwargs,
    attention_mask,
    is_encoder_decoder,
    **forward_kwargs,
) -> torch.Tensor:
    """Apply scoring-time logits processors position-by-position (teacher forcing).

    Processors receive the same `(prefix_ids, scores)` view as during generation. For causal
    models the prefix is `input ++ ref[:t]` when scoring `ref[t]`; for encoder-decoder models
    the prefix is the decoder ids `ref[:t+1]` when scoring `ref[t+1]` (matching the existing
    target alignment in both paths).
    """
    entries = collect_output_entries(
        output_controls, steered_input_ids, runtime_kwargs, attention_mask=attention_mask,
        for_scoring=True, **forward_kwargs,
    )
    processors = [p for entry in entries for p in entry.logits_processors]
    if not processors:
        return logits
    stack = LogitsProcessorList(processors)
    with torch.no_grad():
        for t in range(logits.size(1)):
            prefix = (ref_output_ids[:, : t + 1] if is_encoder_decoder
                      else torch.cat([steered_input_ids, ref_output_ids[:, :t]], dim=1))
            logits[:, t, :] = stack(prefix, logits[:, t, :])
    return logits
collect_output_entries(output_controls, input_ids, runtime_kwargs, *, attention_mask=None, for_scoring=False, skip_ids=frozenset(), **gen_kwargs)

One StackEntry per contributing output control, in controls-list order.

With for_scoring=True, only include_in_scoring controls contribute processors and criteria are skipped (there is no loop to stop). Controls whose id() is in skip_ids (lowered to generation parameters for this call) contribute nothing. Controls contributing neither processors nor criteria yield no entry.

Source code in steerability/algorithms/core/utils/assembly.py
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
def collect_output_entries(
    output_controls: Sequence[OutputControl],
    input_ids,
    runtime_kwargs,
    *,
    attention_mask=None,
    for_scoring=False,
    skip_ids=frozenset(),
    **gen_kwargs,
) -> tuple[StackEntry, ...]:
    """One `StackEntry` per contributing output control, in controls-list order.

    With `for_scoring=True`, only `include_in_scoring` controls contribute processors and
    criteria are skipped (there is no loop to stop). Controls whose `id()` is in `skip_ids`
    (lowered to generation parameters for this call) contribute nothing. Controls
    contributing neither processors nor criteria yield no entry.
    """
    entries: list[StackEntry] = []
    for control in output_controls:
        if not control.enabled or id(control) in skip_ids:
            continue
        if for_scoring and not getattr(control, "include_in_scoring", True):
            logger.info(
                "compute_logprobs: skipping %s (include_in_scoring=False); scored logprobs will "
                "not reflect this control's logits processors.",
                type(control).__name__,
            )
            continue
        processors = control.get_logits_processors(
            input_ids, runtime_kwargs, attention_mask=attention_mask, **gen_kwargs) or []
        criteria = [] if for_scoring else (control.get_stopping_criteria(
            input_ids, runtime_kwargs, attention_mask=attention_mask, **gen_kwargs) or [])
        if processors or criteria:
            entries.append(StackEntry(
                logits_processors=tuple(processors), stopping_criteria=tuple(criteria),
            ))
    return tuple(entries)
collect_state_entries(state_controls, input_ids, runtime_kwargs, *, attention_mask=None, hooks_in_process, lowered_state, backend=None, intervention_kinds=None, model=None, **gen_kwargs)

Collect every enabled state control's entries for the current logical generation.

With hooks_in_process True, hooks are per-generation artifacts built here: they close over the prompt anchor, sized gate state, and a fresh position clock, and travel only as HookEntry contributions (the session that executes forwards owns registration). Otherwise entries come from the steer-time lowering cache, filled lazily for a control enabled after steer().

Parameters:

Name Type Description Default
state_controls Sequence[StateControl]

The pipeline's state controls, in list order.

required
input_ids Tensor

Input token IDs after input control transformation

required
runtime_kwargs dict | None

Per-call parameters for state controls

required
attention_mask Tensor | None

The prompt attention mask matching input_ids. Forwarded to hook construction so condition scorers see the real (non-pad) prompt tokens rather than re-deriving a pad mask by token identity.

None
hooks_in_process bool

Whether the backend executes in-process torch hooks.

required
lowered_state dict[int, InterventionEntry]

Steer-time lowering cache keyed by id(control), updated in place on a lazy fill.

required
backend 'Backend | None'

Inference backend consulted on a lazy fill.

None
intervention_kinds 'InterventionKinds | None'

Advertised kinds verified on a lazy fill.

None
model 'PreTrainedModel | None'

Live model forwarded to hook construction.

None

Returns:

Type Description
tuple[StateControlEntry, ...]

One entry per enabled state control, in controls-list order.

Source code in steerability/algorithms/core/utils/assembly.py
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
def collect_state_entries(
        state_controls: Sequence[StateControl],
        input_ids: torch.Tensor,
        runtime_kwargs: dict | None,
        *,
        attention_mask: torch.Tensor | None = None,
        hooks_in_process: bool,
        lowered_state: dict[int, InterventionEntry],
        backend: "Backend | None" = None,
        intervention_kinds: "InterventionKinds | None" = None,
        model: "PreTrainedModel | None" = None,
        **gen_kwargs,
) -> tuple[StateControlEntry, ...]:
    """Collect every enabled state control's entries for the current logical generation.

    With `hooks_in_process` True, hooks are per-generation artifacts built here: they close
    over the prompt anchor, sized gate state, and a fresh position clock, and travel only as
    `HookEntry` contributions (the session that executes forwards owns registration).
    Otherwise entries come from the steer-time lowering cache, filled lazily for a control
    enabled after `steer()`.

    Args:
        state_controls: The pipeline's state controls, in list order.
        input_ids: Input token IDs after input control transformation
        runtime_kwargs: Per-call parameters for state controls
        attention_mask: The prompt attention mask matching `input_ids`. Forwarded to
            hook construction so condition scorers see the real (non-pad) prompt tokens
            rather than re-deriving a pad mask by token identity.
        hooks_in_process: Whether the backend executes in-process torch hooks.
        lowered_state: Steer-time lowering cache keyed by `id(control)`, updated in place on
            a lazy fill.
        backend: Inference backend consulted on a lazy fill.
        intervention_kinds: Advertised kinds verified on a lazy fill.
        model: Live model forwarded to hook construction.

    Returns:
        One entry per enabled state control, in controls-list order.
    """
    if not hooks_in_process:
        entries = []
        for state_control in state_controls:
            if not state_control.enabled:
                continue
            entry = lowered_state.get(id(state_control))
            if entry is None:
                served = ((getattr(backend, "_discovery", None) or {}).get("model") or {})
                payloads: dict = {}
                entry = _lower_control(
                    state_control, intervention_kinds, served, payloads,
                )
                backend.stage_artifacts(payloads)
                lowered_state[id(state_control)] = entry
            entries.append(entry)
        return tuple(entries)

    entries = []
    for state_control in state_controls:
        if not state_control.enabled:
            continue
        hooks = state_control.get_hooks(
            input_ids, runtime_kwargs, attention_mask=attention_mask, model=model, **gen_kwargs
        )
        entries.append(HookEntry(hooks=hooks))
    return tuple(entries)
compose_stacks(output_controls, input_ids, runtime_kwargs, attention_mask, gen_kwargs, *, skip_ids=frozenset())

Compose the controls' processors and criteria, then append caller extras popped from gen_kwargs (mutates gen_kwargs).

Caller-supplied logits_processor / stopping_criteria entries append after the pipeline's own processors and criteria (per-call extras apply on top of the pipeline's standing configuration) and the keys are removed from gen_kwargs, so exactly one authoritative stack of each kind exists, travelling as an explicit parameter. gen_kwargs reaching the driver never contains processor or criteria objects, so drivers that copy or serialize their kwargs are safe by construction, and a driver that ignores the stacks visibly ignores named parameters.

Source code in steerability/algorithms/core/utils/assembly.py
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
def compose_stacks(
    output_controls: Sequence[OutputControl],
    input_ids,
    runtime_kwargs,
    attention_mask,
    gen_kwargs,
    *,
    skip_ids=frozenset(),
) -> tuple[LogitsProcessorList, StoppingCriteriaList]:
    """Compose the controls' processors and criteria, then append caller extras popped from
    `gen_kwargs` (mutates `gen_kwargs`).

    Caller-supplied `logits_processor` / `stopping_criteria` entries append after the
    pipeline's own processors and criteria (per-call extras apply on top of the pipeline's
    standing configuration) and the keys are removed from `gen_kwargs`, so exactly one
    authoritative stack of each kind exists, travelling as an explicit parameter. gen_kwargs
    reaching the driver never contains processor or criteria objects, so drivers that copy or
    serialize their kwargs are safe by construction, and a driver that ignores the stacks
    visibly ignores named parameters.
    """
    entries = collect_output_entries(
        output_controls, input_ids, runtime_kwargs, attention_mask=attention_mask,
        skip_ids=skip_ids, **gen_kwargs
    )
    processors = [p for entry in entries for p in entry.logits_processors]
    criteria = [c for entry in entries for c in entry.stopping_criteria]
    user_processors = gen_kwargs.pop("logits_processor", None) or []
    user_criteria = gen_kwargs.pop("stopping_criteria", None) or []
    return (
        LogitsProcessorList([*processors, *user_processors]),
        StoppingCriteriaList([*criteria, *user_criteria]),
    )
constraint_contributions(output_controls, runtime_kwargs)

Declarative constraint sources from enabled output controls, keyed by id().

A control that returns a source from export_constraint is lowered for that call on backends hosting structured outputs natively: the source renders onto the engine's request parameters and the control's live processor is not collected.

Source code in steerability/algorithms/core/utils/assembly.py
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
def constraint_contributions(
    output_controls: Sequence[OutputControl],
    runtime_kwargs: dict | None,
) -> dict[int, ConstraintSource]:
    """Declarative constraint sources from enabled output controls, keyed by `id()`.

    A control that returns a source from `export_constraint` is lowered for that call on
    backends hosting structured outputs natively: the source renders onto the engine's
    request parameters and the control's live processor is not collected.
    """
    contributions: dict[int, ConstraintSource] = {}
    for control in output_controls:
        if not control.enabled:
            continue
        exporter = getattr(control, "export_constraint", None)
        source = exporter(runtime_kwargs) if callable(exporter) else None
        if source is not None:
            contributions[id(control)] = source
    return contributions
lower_state_controls(state_controls, backend, capabilities)

Lower every enabled state control's interventions for a spec-consuming backend and stage their artifacts, returning the entries keyed by id(control).

Runs at the end of steer() when the backend executes interventions as specs rather than in-process hooks. Specs are per-steer artifacts: the worker anchors positions per request server-side and the spec is prompt-independent by construction, so one lowering serves every subsequent generation. Each spec is verified against the backend's negotiated kinds (the intersection of the static tables and discovery), and a control's steering-artifact provenance is cross-checked against the served model's when the backend carries a discovery payload. Returns an empty mapping when the backend executes hooks in process, hosts no intervention specs, or no control is enabled.

Raises:

Type Description
UnsupportedOperationError

If an enabled control's configuration has no wire form (the failure names the control, the intervention, and the reason), or its spec requires a kind the backend does not advertise.

Source code in steerability/algorithms/core/utils/assembly.py
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
def lower_state_controls(
        state_controls: Sequence[StateControl],
        backend,
        capabilities: BackendCapabilities,
) -> dict[int, InterventionEntry]:
    """Lower every enabled state control's interventions for a spec-consuming backend and
    stage their artifacts, returning the entries keyed by `id(control)`.

    Runs at the end of `steer()` when the backend executes interventions as
    specs rather than in-process hooks. Specs are per-steer artifacts: the worker anchors
    positions per request server-side and the spec is prompt-independent by construction,
    so one lowering serves every subsequent generation. Each spec is verified against the
    backend's negotiated kinds (the intersection of the static tables and discovery), and
    a control's steering-artifact provenance is cross-checked against the served model's
    when the backend carries a discovery payload. Returns an empty mapping when the backend
    executes hooks in process, hosts no intervention specs, or no control is enabled.

    Raises:
        UnsupportedOperationError: If an enabled control's configuration has no wire form
            (the failure names the control, the intervention, and the reason), or its spec
            requires a kind the backend does not advertise.
    """
    if Capability.IN_PROCESS_TORCH in capabilities.atoms:
        return {}
    if Capability.INTERVENTION_SPECS not in capabilities.atoms:
        return {}
    enabled = [c for c in state_controls if c.enabled]
    if not enabled:
        return {}

    advertised = capabilities.intervention_kinds
    served_model = ((getattr(backend, "_discovery", None) or {}).get("model") or {})
    payloads: dict = {}
    lowered: dict[int, InterventionEntry] = {}
    for state_control in enabled:
        lowered[id(state_control)] = _lower_control(
            state_control, advertised, served_model, payloads,
        )
    backend.stage_artifacts(payloads)
    return lowered
lowered_contributions(output_controls, runtime_kwargs)

Sampling-expressible contributions from enabled output controls, keyed by id().

A control that returns a mapping from export_generation_params is lowered for this call: its contribution merges into the call's GenerationParams and its live processor and criteria hooks are not collected.

Source code in steerability/algorithms/core/utils/assembly.py
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
def lowered_contributions(
    output_controls: Sequence[OutputControl],
    runtime_kwargs: dict | None,
) -> dict[int, Mapping]:
    """Sampling-expressible contributions from enabled output controls, keyed by `id()`.

    A control that returns a mapping from `export_generation_params` is lowered for this
    call: its contribution merges into the call's `GenerationParams` and its live processor
    and criteria hooks are not collected.
    """
    contributions: dict[int, Mapping] = {}
    for control in output_controls:
        if not control.enabled:
            continue
        exporter = getattr(control, "export_generation_params", None)
        contribution = exporter(runtime_kwargs) if callable(exporter) else None
        if contribution is not None:
            contributions[id(control)] = contribution
    return contributions
per_item_state_entries(state_controls, input_ids, attention_mask, runtime_kwargs, *, model=None, **gen_kwargs)

Per-row state entries computed by per-call control clones.

Distinct per-item derived seeds force the in-process session onto its serial path, where each row runs its own forward. Hooks computed once on the batch hold batch-sized position and gate state, so each row instead gets hooks computed by a fresh clone on that row's prompt tensors.

Parameters:

Name Type Description Default
state_controls Sequence[StateControl]

The pipeline's state controls, in list order.

required
input_ids Tensor

Adapted prompt ids of shape [batch, seq_len].

required
attention_mask Tensor

Attention mask matching input_ids.

required
runtime_kwargs dict | None

Per-call parameters for state controls.

required
model 'PreTrainedModel | None'

Live model forwarded to get_hooks().

None

Returns:

Type Description
list[tuple[HookEntry, ...]]

One tuple of HookEntry per row, each in controls-list order.

Source code in steerability/algorithms/core/utils/assembly.py
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
def per_item_state_entries(
        state_controls: Sequence[StateControl],
        input_ids: torch.Tensor,
        attention_mask: torch.Tensor,
        runtime_kwargs: dict | None,
        *,
        model: "PreTrainedModel | None" = None,
        **gen_kwargs,
) -> list[tuple[HookEntry, ...]]:
    """Per-row state entries computed by per-call control clones.

    Distinct per-item derived seeds force the in-process session onto its serial path, where
    each row runs its own forward. Hooks computed once on the batch hold batch-sized position
    and gate state, so each row instead gets hooks computed by a fresh clone on that row's
    prompt tensors.

    Args:
        state_controls: The pipeline's state controls, in list order.
        input_ids: Adapted prompt ids of shape `[batch, seq_len]`.
        attention_mask: Attention mask matching `input_ids`.
        runtime_kwargs: Per-call parameters for state controls.
        model: Live model forwarded to `get_hooks()`.

    Returns:
        One tuple of `HookEntry` per row, each in controls-list order.
    """
    rows: list[tuple[HookEntry, ...]] = []
    for index in range(input_ids.size(0)):
        entries: list[HookEntry] = []
        for state_control in state_controls:
            if not state_control.enabled:
                continue
            clone = state_control.clone_for_call()
            hooks = clone.get_hooks(
                input_ids[index:index + 1],
                runtime_kwargs,
                attention_mask=attention_mask[index:index + 1],
                model=model,
                **gen_kwargs,
            )
            entries.append(HookEntry(hooks=hooks))
        rows.append(tuple(entries))
    return rows
processor_spec_contributions(output_controls, runtime_kwargs, capabilities)

Engine-hosted processor contributions from enabled output controls, keyed by id().

A control that returns a ProcessorSpec from export_processor_spec whose kind the backend serves is lowered for that call: the spec travels as a ProcessorSpecEntry and the control's live processor is not collected. The lowering choice is a ladder, highest supported rung first: normalized parameters, then engine-hosted specs, then live processors.

Source code in steerability/algorithms/core/utils/assembly.py
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
def processor_spec_contributions(
    output_controls: Sequence[OutputControl],
    runtime_kwargs: dict | None,
    capabilities: BackendCapabilities,
) -> dict[int, ProcessorSpecEntry]:
    """Engine-hosted processor contributions from enabled output controls, keyed by `id()`.

    A control that returns a `ProcessorSpec` from `export_processor_spec` whose kind the
    backend serves is lowered for that call: the spec travels as a `ProcessorSpecEntry`
    and the control's live processor is not collected. The lowering choice is a ladder,
    highest supported rung first: normalized parameters, then engine-hosted specs, then
    live processors.
    """
    served = capabilities.processor_kinds
    if served is None:
        return {}
    contributions: dict[int, ProcessorSpecEntry] = {}
    for control in output_controls:
        if not control.enabled:
            continue
        exporter = getattr(control, "export_processor_spec", None)
        spec = exporter(runtime_kwargs) if callable(exporter) else None
        if spec is not None and spec.kind in served.processors:
            contributions[id(control)] = ProcessorSpecEntry(spec=spec)
    return contributions
resolve_decoding_driver(output_controls)

The sole enabled DecodingDriver, or None for the pipeline's default decode loop.

merge_controls guarantees at most one enabled driver at construction; enabled is re-checked here so a driver disabled afterward falls back cleanly. The default loop (per-prompt items executed by the inference session) is pipeline infrastructure, not a phantom control.

Source code in steerability/algorithms/core/utils/assembly.py
356
357
358
359
360
361
362
363
364
365
366
367
def resolve_decoding_driver(output_controls: Sequence[OutputControl]) -> DecodingDriver | None:
    """The sole enabled DecodingDriver, or None for the pipeline's default decode loop.

    merge_controls guarantees at most one enabled driver at construction; `enabled` is
    re-checked here so a driver disabled afterward falls back cleanly. The default loop
    (per-prompt items executed by the inference session) is pipeline infrastructure, not a
    phantom control.
    """
    for control in output_controls:
        if isinstance(control, DecodingDriver) and control.enabled:
            return control
    return None
rollout_entries(state_entries, steered_input_ids, steered_attention_mask)

Rollout variants of the lowered entries for a driver on a spec-consuming backend.

Prompt-relative scopes are rewritten to absolute positions at the generation's original prompt boundary. The rewrite needs one exact anchor per generation, and a rollout item cannot be traced back to a batch row, so uneven batches (rows whose true prompt lengths differ under padding) are refused. Conditional gates are refused too: a worker gate re-anchors its evidence at each rollout request's own prompt end, which would decide from generated text instead of the original prompt.

Raises:

Type Description
UnsupportedOperationError

If the batch is uneven, a scope has no absolute rollout form, or an entry carries a conditional gate.

Source code in steerability/algorithms/core/utils/assembly.py
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
def rollout_entries(state_entries, steered_input_ids, steered_attention_mask) -> tuple:
    """Rollout variants of the lowered entries for a driver on a spec-consuming backend.

    Prompt-relative scopes are rewritten to absolute positions at the generation's
    original prompt boundary. The rewrite needs one exact anchor per generation, and a
    rollout item cannot be traced back to a batch row, so uneven batches (rows whose true
    prompt lengths differ under padding) are refused. Conditional gates are refused too:
    a worker gate re-anchors its evidence at each rollout request's own prompt end, which
    would decide from generated text instead of the original prompt.

    Raises:
        UnsupportedOperationError: If the batch is uneven, a scope has no absolute rollout
            form, or an entry carries a conditional gate.
    """
    if steered_attention_mask is not None and not bool(steered_attention_mask.bool().all()):
        raise UnsupportedOperationError(
            "Driver rollouts on a spec-consuming backend need one exact prompt anchor per "
            "generation, and padded batch rows have per-row anchors; submit prompts of "
            "equal length, one prompt per call, or run this pipeline on the huggingface "
            "backend."
        )
    anchor = steered_input_ids.size(1)
    rollout_entries = []
    for entry in state_entries:
        if not isinstance(entry, InterventionEntry):
            rollout_entries.append(entry)
            continue
        if any(op.get("gate") is not None for op in entry.spec.to_wire()["ops"]):
            raise UnsupportedOperationError(
                "Conditional gating has no rollout form on a spec-consuming backend: the "
                "worker anchors gate evidence at each rollout request's own prompt end; "
                "run gated controls under a decoding driver on the huggingface backend."
            )
        try:
            rewritten = remap_prompt_relative_scopes(entry.spec, anchor)
        except ValueError as error:
            raise UnsupportedOperationError(str(error)) from error
        rollout_entries.append(InterventionEntry(spec=rewritten))
    return tuple(rollout_entries)

auxiliary_pass

Marking for forward passes through the pipeline's model that are not generation steps.

Output-control components that forward the pipeline's own model during decoding wrap those calls in auxiliary_pass(). State-control accounting consults current_auxiliary_pass() to keep auxiliary passes out of condition scoring, gate updates, and fallback position counting. aligned declares whether the pass's token positions lie on the current generation's coordinate axis (a prefix of the trajectory, or a prefix plus a candidate next token) or on a detached sequence such as a transformed prompt.

AuxiliaryPassInfo dataclass

Describes the auxiliary pass currently in flight.

Attributes:

Name Type Description
aligned bool

True when the pass's token positions lie on the current generation's coordinate axis. False for a detached sequence.

Source code in steerability/algorithms/core/utils/auxiliary_pass.py
17
18
19
20
21
22
23
24
25
26
@dataclass(frozen=True)
class AuxiliaryPassInfo:
    """Describes the auxiliary pass currently in flight.

    Attributes:
        aligned: True when the pass's token positions lie on the current generation's coordinate
            axis. False for a detached sequence.
    """

    aligned: bool
aligned instance-attribute
auxiliary_pass(*, aligned=True)

Mark model forwards issued inside the block as auxiliary (not generation steps).

Source code in steerability/algorithms/core/utils/auxiliary_pass.py
34
35
36
37
38
39
40
41
@contextlib.contextmanager
def auxiliary_pass(*, aligned: bool = True):
    """Mark model forwards issued inside the block as auxiliary (not generation steps)."""
    token = _CURRENT.set(AuxiliaryPassInfo(aligned=aligned))
    try:
        yield
    finally:
        _CURRENT.reset(token)
current_auxiliary_pass()

The in-flight auxiliary pass marker, or None during ordinary generation passes.

Source code in steerability/algorithms/core/utils/auxiliary_pass.py
44
45
46
def current_auxiliary_pass() -> AuxiliaryPassInfo | None:
    """The in-flight auxiliary pass marker, or None during ordinary generation passes."""
    return _CURRENT.get()

controls

Helpers for working with control objects: composition/validation and adapt-messages guards.

merge_controls(supplied)

Sort supplied controls by category.

Every category admits any number of controls, returned as ordered lists (in encounter order) under "input_controls", "structural_controls", "state_controls", and "output_controls". An omitted category is an empty list; every application of a category is a fold over its list, whose identity element is the empty sequence (the prompt threads through the adapt chain, the model threads through structural steers, state and output entries accumulate).

The output category additionally admits at most one enabled DecodingDriver; the decode loop does not compose. Input controls chain in two phases (message-level, then token-level); see SteeringPipeline.generate for the per-control application contract.

Parameters:

Name Type Description Default
supplied Iterable[StructuralControl | StateControl | InputControl | OutputControl]

List of control instances to organize

required

Returns:

Type Description
dict[str, object]

Dict with keys "input_controls", "structural_controls", "state_controls", and

dict[str, object]

"output_controls", each an ordered list of controls (empty for unspecified categories).

Raises:

Type Description
ValueError

If the same control instance is supplied more than once, or if more than one enabled DecodingDriver is supplied

TypeError

If an unrecognized control type is supplied

Source code in steerability/algorithms/core/utils/controls.py
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
def merge_controls(
        supplied: Iterable[StructuralControl | StateControl | InputControl | OutputControl]
) -> dict[str, object]:
    """Sort supplied controls by category.

    Every category admits any number of controls, returned as ordered lists (in encounter order)
    under `"input_controls"`, `"structural_controls"`, `"state_controls"`, and `"output_controls"`.
    An omitted category is an empty list; every application of a category is a fold over its
    list, whose identity element is the empty sequence (the prompt threads through the adapt
    chain, the model threads through structural steers, state and output entries accumulate).

    The output category additionally admits at most one enabled `DecodingDriver`; the decode loop
    does not compose. Input controls chain in two phases (message-level, then token-level); see
    `SteeringPipeline.generate` for the per-control application contract.

    Args:
       supplied: List of control instances to organize

    Returns:
       Dict with keys `"input_controls"`, `"structural_controls"`, `"state_controls"`, and
       `"output_controls"`, each an ordered list of controls (empty for unspecified categories).

    Raises:
       ValueError: If the same control instance is supplied more than once, or if more than one
           enabled `DecodingDriver` is supplied
       TypeError: If an unrecognized control type is supplied
    """
    supplied = list(supplied)

    # reject the same control instance supplied twice
    seen_ids: set[int] = set()
    for control in supplied:
        if id(control) in seen_ids:
            raise ValueError(
                f"The same {type(control).__name__} instance was supplied more than once. "
                "To apply a method twice, construct a second instance."
            )
        seen_ids.add(id(control))

    bucket: dict[type, list] = defaultdict(list)
    for control in supplied:
        for category in _CATEGORIES:
            if isinstance(control, category):
                bucket[category].append(control)
                break
        else:
            raise TypeError(f"Unknown control type: {type(control)}")

    # at most one enabled DecodingDriver; the decode loop does not compose
    drivers = [
        control for control in bucket.get(OutputControl, [])
        if isinstance(control, DecodingDriver) and getattr(control, "enabled", True)
    ]
    if len(drivers) > 1:
        names = [type(control).__name__ for control in drivers]
        raise ValueError(
            f"Multiple decoding drivers supplied: {names}. The decode loop does not compose; "
            "keep one DecodingDriver and express the rest as logits processors or stopping criteria."
        )

    return {
        "input_controls": list(bucket.get(InputControl, [])),
        "structural_controls": list(bucket.get(StructuralControl, [])),
        "state_controls": list(bucket.get(StateControl, [])),
        "output_controls": list(bucket.get(OutputControl, [])),
    }
runtime_kwargs_schema(controls)

Merge the RUNTIME_KWARGS_SCHEMA declarations of the enabled controls, by name.

Each declared entry carries name plus optional type, required, help, and scope fields. scope is "row" for a per-prompt value (in a batched call the control receives a sequence with one element per prompt row, in row order) or "call" for one value per generate call regardless of batch size; an entry without scope is "call". Two controls may declare one name only when their declarations agree, in which case they share one value at inference time.

Parameters:

Name Type Description Default
controls Iterable[StructuralControl | StateControl | InputControl | OutputControl]

Control instances whose enabled members' declarations are merged.

required

Returns:

Type Description
dict[str, dict]

Mapping from declared name to its merged entry, with scope normalized to "row" or

dict[str, dict]

"call". For a name declared by several controls, the first declaration's other fields

dict[str, dict]

are kept.

Raises:

Type Description
ValueError

If an entry's scope is neither "row" nor "call" (naming the control and the entry), or if two controls declare one name with a different scope or type (naming both controls).

Source code in steerability/algorithms/core/utils/controls.py
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
def runtime_kwargs_schema(
        controls: Iterable[StructuralControl | StateControl | InputControl | OutputControl]
) -> dict[str, dict]:
    """Merge the `RUNTIME_KWARGS_SCHEMA` declarations of the enabled controls, by name.

    Each declared entry carries `name` plus optional `type`, `required`, `help`, and `scope`
    fields. `scope` is `"row"` for a per-prompt value (in a batched call the control receives a
    sequence with one element per prompt row, in row order) or `"call"` for one value per
    `generate` call regardless of batch size; an entry without `scope` is `"call"`. Two controls
    may declare one name only when their declarations agree, in which case they share one value at
    inference time.

    Args:
        controls: Control instances whose enabled members' declarations are merged.

    Returns:
        Mapping from declared name to its merged entry, with `scope` normalized to `"row"` or
        `"call"`. For a name declared by several controls, the first declaration's other fields
        are kept.

    Raises:
        ValueError: If an entry's `scope` is neither `"row"` nor `"call"` (naming the control and
            the entry), or if two controls declare one name with a different `scope` or `type`
            (naming both controls).
    """
    merged: dict[str, dict] = {}
    owners: dict[str, str] = {}
    for control in controls:
        if not getattr(control, "enabled", True):
            continue
        control_name = type(control).__name__
        for entry in getattr(control, "RUNTIME_KWARGS_SCHEMA", []):
            name = entry.get("name")
            if not name:
                continue
            scope = entry.get("scope", "call")
            if scope not in ("row", "call"):
                raise ValueError(
                    f"{control_name} declares runtime kwarg {name!r} with invalid scope {scope!r}; "
                    "scope must be 'row' or 'call'."
                )
            if name not in merged:
                merged[name] = {**entry, "scope": scope}
                owners[name] = control_name
                continue
            existing = merged[name]
            if existing["scope"] != scope:
                raise ValueError(
                    f"{owners[name]} and {control_name} declare runtime kwarg {name!r} with different "
                    f"scopes ({existing['scope']!r} vs {scope!r})."
                )
            existing_type = existing.get("type")
            new_type = entry.get("type")
            if existing_type is not None and new_type is not None and existing_type != new_type:
                raise ValueError(
                    f"{owners[name]} and {control_name} declare runtime kwarg {name!r} with different "
                    f"types ({existing_type!r} vs {new_type!r})."
                )
    return merged
warn_if_adapt_messages_bypassed(input_controls, already_warned)

Warn (UserWarning) when any control in input_controls overrides adapt_messages but the caller used tensor/text input, bypassing chat-template tokenization. The warning names each bypassed control class. Returns the updated warned-state.

Parameters:

Name Type Description Default
input_controls list[InputControl]

The pipeline's input controls, in list order.

required
already_warned bool

Whether the bypass warning has already fired for this pipeline.

required

Returns:

Type Description
bool

The updated warned-state.

Source code in steerability/algorithms/core/utils/controls.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
def warn_if_adapt_messages_bypassed(input_controls: list[InputControl], already_warned: bool) -> bool:
    """Warn (UserWarning) when any control in `input_controls` overrides `adapt_messages` but the
    caller used tensor/text input, bypassing chat-template tokenization. The warning names each
    bypassed control class. Returns the updated warned-state.

    Args:
        input_controls: The pipeline's input controls, in list order.
        already_warned: Whether the bypass warning has already fired for this pipeline.

    Returns:
        The updated warned-state.
    """
    if already_warned:
        return already_warned
    bypassed = [
        type(control).__name__
        for control in input_controls
        if type(control).adapt_messages is not InputControl.adapt_messages
    ]
    if bypassed:
        warnings.warn(
            f"{', '.join(bypassed)} override(s) `adapt_messages` but received tensor/text input; "
            "the message-level adaptation will not run. Pass `list[dict]` or `list[list[dict]]` "
            "to engage `adapt_messages`.",
            UserWarning,
        )
        return True
    return already_warned

generation

Prompt resolution helpers for SteeringPipeline: source dispatch, per-modality validation and tokenization, message-level adaptation, and the token-level adapt chain.

PromptWarnings dataclass

Once-per-pipeline warning flags for prompt resolution.

Source code in steerability/algorithms/core/utils/generation.py
20
21
22
23
24
25
@dataclass
class PromptWarnings:
    """Once-per-pipeline warning flags for prompt resolution."""

    tensor_with_adapt_messages: bool = False
    duplicate_bos: bool = False
duplicate_bos = False class-attribute instance-attribute
tensor_with_adapt_messages = False class-attribute instance-attribute
apply_adapt_messages_and_tokenize(input_controls, tokenizer, messages_batch, runtime_kwargs, chat_template_kwargs=None)

Fold every input control's adapt_messages over the message batch, then chat-template tokenize once.

Controls run in list order. A non-None return becomes the input to the next control and marks that control as handled at message level; a None return passes the messages through unchanged and leaves the control unmarked, so the pipeline later runs its token-level adapt instead. Each control is therefore applied exactly once per call.

Parameters:

Name Type Description Default
input_controls 'list[InputControl]'

Input controls whose adapt_messages runs in list order.

required
tokenizer 'PreTrainedTokenizerBase'

Tokenizer whose apply_chat_template performs the tokenization.

required
messages_batch list[list[dict]]

One conversation per row, each a list of chat-message mappings.

required
runtime_kwargs dict

Per-call parameters forwarded to adapt_messages.

required
chat_template_kwargs dict | None

Extra keyword arguments forwarded to apply_chat_template after the four pipeline-owned kwargs (return_tensors, padding, add_generation_prompt, return_dict). None or an empty mapping adds nothing. The toolkit does not interpret the keys; they are model-family specific (e.g. enable_thinking).

None

Returns:

Type Description
Tensor

tuple[input_ids, attention_mask, handled] where handled contains id(control) for each

Tensor | None

control whose adapt_messages returned a non-None result.

Source code in steerability/algorithms/core/utils/generation.py
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
def apply_adapt_messages_and_tokenize(
        input_controls: "list[InputControl]",
        tokenizer: "PreTrainedTokenizerBase",
        messages_batch: list[list[dict]],
        runtime_kwargs: dict,
        chat_template_kwargs: dict | None = None,
) -> tuple[torch.Tensor, torch.Tensor | None, set[int]]:
    """Fold every input control's `adapt_messages` over the message batch, then chat-template tokenize once.

    Controls run in list order. A non-None return becomes the input to the next control and marks
    that control as handled at message level; a None return passes the messages through unchanged
    and leaves the control unmarked, so the pipeline later runs its token-level `adapt` instead.
    Each control is therefore applied exactly once per call.

    Args:
        input_controls: Input controls whose `adapt_messages` runs in list order.
        tokenizer: Tokenizer whose `apply_chat_template` performs the tokenization.
        messages_batch: One conversation per row, each a list of chat-message mappings.
        runtime_kwargs: Per-call parameters forwarded to `adapt_messages`.
        chat_template_kwargs: Extra keyword arguments forwarded to `apply_chat_template` after the
            four pipeline-owned kwargs (`return_tensors`, `padding`, `add_generation_prompt`,
            `return_dict`). None or an empty mapping adds nothing. The toolkit does not interpret
            the keys; they are model-family specific (e.g. `enable_thinking`).

    Returns:
        tuple[input_ids, attention_mask, handled] where `handled` contains `id(control)` for each
        control whose `adapt_messages` returned a non-None result.
    """
    handled: set[int] = set()
    for control in input_controls:
        adapted = control.adapt_messages(
            messages_batch,
            runtime_kwargs=runtime_kwargs,
        )
        if adapted is not None:
            messages_batch = adapted
            handled.add(id(control))

    encoded = tokenizer.apply_chat_template(
        messages_batch,
        return_tensors="pt",
        padding=True,
        add_generation_prompt=True,
        return_dict=True,
        **(chat_template_kwargs or {}),
    )
    input_ids = encoded["input_ids"]
    attention_mask = encoded.get("attention_mask")
    if input_ids.ndim == 1:
        input_ids = input_ids.unsqueeze(0)
        if attention_mask is not None and attention_mask.ndim == 1:
            attention_mask = attention_mask.unsqueeze(0)
    return input_ids, attention_mask, handled
prepare_inputs(input_ids, attention_mask, *, input_controls, tokenizer, device, runtime_kwargs, message_handled=frozenset(), warnings_state)

Apply the token-level input-control chain and normalize input tensors.

Runs each input control's adapt in list order (each control receives the previous control's output), then ensures both input_ids and attention_mask are properly shaped tensors on the correct device.

Parameters:

Name Type Description Default
input_ids list[int] | LongTensor

Input token IDs as list or tensor [seq_len] or [batch, seq_len]

required
attention_mask Tensor | None

Optional attention mask matching input_ids shape

required
input_controls 'list[InputControl]'

Input controls whose token-level adapt runs in list order.

required
tokenizer 'PreTrainedTokenizerBase | None'

Tokenizer consulted for pad-token mask inference and the duplicate-bos check.

required
device device

Device the returned tensors are moved to.

required
runtime_kwargs dict | None

Per-call parameters for input controls

required
message_handled frozenset[int]

id()s of input controls whose adapt_messages already performed the adaptation before tokenization for this call; their token-level adapt is skipped so no control is applied twice to the same prompt.

frozenset()
warnings_state PromptWarnings

Once-per-pipeline warning flags, updated in place.

required

Returns:

Type Description
tuple[Tensor, Tensor]

tuple[torch.Tensor, torch.Tensor]: (steered_input_ids, attention_mask), both as 2D tensors on device

Source code in steerability/algorithms/core/utils/generation.py
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
def prepare_inputs(
        input_ids: list[int] | torch.LongTensor,
        attention_mask: torch.Tensor | None,
        *,
        input_controls: "list[InputControl]",
        tokenizer: "PreTrainedTokenizerBase | None",
        device: torch.device,
        runtime_kwargs: dict | None,
        message_handled: frozenset[int] = frozenset(),
        warnings_state: PromptWarnings,
) -> tuple[torch.Tensor, torch.Tensor]:
    """Apply the token-level input-control chain and normalize input tensors.

    Runs each input control's `adapt` in list order (each control receives the previous
    control's output), then ensures both input_ids and attention_mask are properly shaped
    tensors on the correct device.

    Args:
        input_ids: Input token IDs as list or tensor [seq_len] or [batch, seq_len]
        attention_mask: Optional attention mask matching input_ids shape
        input_controls: Input controls whose token-level `adapt` runs in list order.
        tokenizer: Tokenizer consulted for pad-token mask inference and the duplicate-bos check.
        device: Device the returned tensors are moved to.
        runtime_kwargs: Per-call parameters for input controls
        message_handled: `id()`s of input controls whose `adapt_messages` already performed the
            adaptation before tokenization for this call; their token-level `adapt` is skipped so
            no control is applied twice to the same prompt.
        warnings_state: Once-per-pipeline warning flags, updated in place.

    Returns:
        tuple[torch.Tensor, torch.Tensor]: (steered_input_ids, attention_mask), both as 2D tensors on `device`
    """
    runtime_kwargs = runtime_kwargs or {}

    # token-phase chain (controls already handled at message level are skipped)
    steered_input_ids = input_ids
    for control in input_controls:
        if id(control) in message_handled:
            continue
        steered_input_ids = control.adapt(
            steered_input_ids,
            runtime_kwargs=runtime_kwargs,
        )

    # normalize input_ids to 2D tensor
    if isinstance(steered_input_ids, list):
        steered_input_ids = torch.tensor(steered_input_ids, dtype=torch.long)
    if steered_input_ids.ndim == 1:
        steered_input_ids = steered_input_ids.unsqueeze(0)
    steered_input_ids = steered_input_ids.to(device)

    # normalize attention_mask
    if attention_mask is not None:
        if isinstance(attention_mask, list):
            attention_mask = torch.as_tensor(attention_mask, dtype=torch.long)
        if attention_mask.ndim == 1:
            attention_mask = attention_mask.unsqueeze(0)
        # rebuild if length mismatch after input control transformation
        if attention_mask.shape[-1] != steered_input_ids.shape[-1]:
            attention_mask = None

    if attention_mask is None:
        if tokenizer is not None and tokenizer.pad_token_id is not None:
            attention_mask = infer_attention_mask_from_ids(steered_input_ids, tokenizer.pad_token_id)
        else:
            attention_mask = torch.ones_like(steered_input_ids, dtype=torch.long)

    attention_mask = attention_mask.to(dtype=steered_input_ids.dtype, device=device)

    warnings_state.duplicate_bos = warn_if_duplicate_bos(
        steered_input_ids, attention_mask, tokenizer, warnings_state.duplicate_bos
    )

    return steered_input_ids, attention_mask
resolve_generate_source(inputs, text, messages, input_ids)

Select the single prompt source and its modality.

Exactly one of positional inputs, text=, messages=, or input_ids= may be provided. Positional input is a convenience for text prompts (str or a list whose every element is a str) and routes to text; any other positional shape raises (E12). Because the check is a total all(...) over the list, a mixed list such as ["a", {"role": ...}] fails here rather than downstream.

Returns:

Type Description
Literal['text', 'messages', 'tokens']

tuple[kind, payload] where kind is "text", "messages", or "tokens" and payload

Any

is the value handed to the matching resolver.

Raises:

Type Description
TypeError

If no source or more than one source is provided (E1/E2), or a positional input is neither a str nor a list[str] (E12).

Source code in steerability/algorithms/core/utils/generation.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
def resolve_generate_source(
        inputs: Any,
        text: Any,
        messages: Any,
        input_ids: Any,
) -> tuple[Literal["text", "messages", "tokens"], Any]:
    """Select the single prompt source and its modality.

    Exactly one of positional `inputs`, `text=`, `messages=`, or `input_ids=` may be provided.
    Positional input is a convenience for text prompts (`str` or a `list` whose every element is
    a `str`) and routes to text; any other positional shape raises (E12). Because the check is a
    total `all(...)` over the list, a mixed list such as `["a", {"role": ...}]` fails here rather
    than downstream.

    Returns:
        tuple[kind, payload] where `kind` is `"text"`, `"messages"`, or `"tokens"` and `payload`
        is the value handed to the matching resolver.

    Raises:
        TypeError: If no source or more than one source is provided (E1/E2), or a positional
            input is neither a `str` nor a `list[str]` (E12).
    """
    provided = [
        name for name, value in (
            ("inputs", inputs), ("text", text), ("messages", messages), ("input_ids", input_ids),
        ) if value is not None
    ]
    if len(provided) == 0:
        raise TypeError(
            "generate() requires a prompt: pass positional text, or exactly one of text=, "
            "messages=, input_ids=."
        )
    if len(provided) > 1:
        names = ", ".join(provided)
        raise TypeError(
            f"generate() received multiple prompt sources ({names}); pass exactly one of "
            "positional inputs, text=, messages=, input_ids=."
        )

    if text is not None:
        return "text", text
    if messages is not None:
        return "messages", messages
    if input_ids is not None:
        return "tokens", input_ids

    # positional inputs: text convenience only
    if isinstance(inputs, str) or (
        isinstance(inputs, list) and all(isinstance(element, str) for element in inputs)
    ):
        return "text", inputs
    raise TypeError(
        "positional input to generate() must be a str or list of str; pass messages=... "
        "for chat or input_ids=... for token input."
    )
resolve_messages_prompt(messages, runtime_kwargs, *, input_controls, tokenizer, chat_template_kwargs=None)

Validate a chat prompt, then adapt and chat-template tokenize it (design §4.3.2).

Accepts one conversation (a sequence of mappings) or a batch (a sequence of sequences of mappings). Message elements are validated as collections.abc.Mapping; role/content schema remains the responsibility of apply_chat_template.

Parameters:

Name Type Description Default
messages Any

One conversation or a batch of conversations.

required
runtime_kwargs dict

Per-call parameters forwarded to adapt_messages.

required
input_controls 'list[InputControl]'

Input controls whose adapt_messages runs in list order.

required
tokenizer 'PreTrainedTokenizerBase'

Tokenizer whose apply_chat_template performs the tokenization.

required
chat_template_kwargs dict | None

Extra keyword arguments forwarded to apply_chat_template after the pipeline-owned kwargs. None or an empty mapping adds nothing.

None

Returns:

Type Description
Tensor

tuple[input_ids, attention_mask, message_handled, is_single], where message_handled

Tensor | None

holds id()s of controls that adapted at message level.

Raises:

Type Description
ValueError

If the conversation or batch is empty (E5).

TypeError

If a batch inner element is not a mapping (E6) or the outer sequence mixes element kinds (E7).

Source code in steerability/algorithms/core/utils/generation.py
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
def resolve_messages_prompt(
        messages: Any,
        runtime_kwargs: dict,
        *,
        input_controls: "list[InputControl]",
        tokenizer: "PreTrainedTokenizerBase",
        chat_template_kwargs: dict | None = None,
) -> tuple[torch.Tensor, torch.Tensor | None, set[int], bool]:
    """Validate a chat prompt, then adapt and chat-template tokenize it (design §4.3.2).

    Accepts one conversation (a sequence of mappings) or a batch (a sequence of sequences of
    mappings). Message elements are validated as `collections.abc.Mapping`; role/content schema
    remains the responsibility of `apply_chat_template`.

    Args:
        messages: One conversation or a batch of conversations.
        runtime_kwargs: Per-call parameters forwarded to `adapt_messages`.
        input_controls: Input controls whose `adapt_messages` runs in list order.
        tokenizer: Tokenizer whose `apply_chat_template` performs the tokenization.
        chat_template_kwargs: Extra keyword arguments forwarded to `apply_chat_template` after the
            pipeline-owned kwargs. None or an empty mapping adds nothing.

    Returns:
        tuple[input_ids, attention_mask, message_handled, is_single], where `message_handled`
        holds `id()`s of controls that adapted at message level.

    Raises:
        ValueError: If the conversation or batch is empty (E5).
        TypeError: If a batch inner element is not a mapping (E6) or the outer sequence mixes
            element kinds (E7).
    """
    outer = list(messages)
    if len(outer) == 0:
        raise ValueError("messages= received an empty conversation or batch.")

    if all(isinstance(element, Mapping) for element in outer):
        is_single = True
        normalized = [list(outer)]
    elif all(isinstance(element, (list, tuple)) for element in outer):
        is_single = False
        normalized = []
        for i, chat in enumerate(outer):
            chat = list(chat)
            if len(chat) == 0:
                raise ValueError("messages= received an empty conversation or batch.")
            for j, message in enumerate(chat):
                if not isinstance(message, Mapping):
                    raise TypeError(
                        f"messages[{i}][{j}] must be a mapping (one chat message); got "
                        f"{type(message).__name__}."
                    )
            normalized.append(chat)
    else:
        raise TypeError(
            "messages= must be one conversation (a sequence of mappings) or a batch (a sequence "
            "of sequences of mappings); got mixed element types at the outer level."
        )

    input_ids, attention_mask, message_handled = apply_adapt_messages_and_tokenize(
        input_controls, tokenizer, normalized, runtime_kwargs,
        chat_template_kwargs=chat_template_kwargs,
    )
    return input_ids, attention_mask, message_handled, is_single
resolve_text_prompt(text, *, input_controls, tokenizer, warnings_state)

Validate and tokenize a text prompt (design §4.3.1).

Parameters:

Name Type Description Default
text Any

A str (single) or a list/tuple whose elements are all str (batch).

required
input_controls 'list[InputControl]'

Input controls consulted for the bypass warning.

required
tokenizer 'PreTrainedTokenizerBase'

Tokenizer used for plain-text tokenization.

required
warnings_state PromptWarnings

Once-per-pipeline warning flags, updated in place.

required

Returns:

Type Description
tuple[Tensor, Tensor | None, bool]

tuple[input_ids, attention_mask, is_single].

Raises:

Type Description
TypeError

If text is a sequence containing a non-str element (E3).

ValueError

If text is an empty sequence (E4).

Source code in steerability/algorithms/core/utils/generation.py
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
def resolve_text_prompt(
        text: Any,
        *,
        input_controls: "list[InputControl]",
        tokenizer: "PreTrainedTokenizerBase",
        warnings_state: PromptWarnings,
) -> tuple[torch.Tensor, torch.Tensor | None, bool]:
    """Validate and tokenize a text prompt (design §4.3.1).

    Args:
        text: A `str` (single) or a `list`/`tuple` whose elements are all `str` (batch).
        input_controls: Input controls consulted for the bypass warning.
        tokenizer: Tokenizer used for plain-text tokenization.
        warnings_state: Once-per-pipeline warning flags, updated in place.

    Returns:
        tuple[input_ids, attention_mask, is_single].

    Raises:
        TypeError: If `text` is a sequence containing a non-`str` element (E3).
        ValueError: If `text` is an empty sequence (E4).
    """
    is_single = isinstance(text, str)
    if is_single:
        normalized = [text]
    else:
        normalized = list(text)
        if len(normalized) == 0:
            raise ValueError("text= received an empty sequence.")
        for index, element in enumerate(normalized):
            if not isinstance(element, str):
                raise TypeError(
                    f"text= must be a str or a sequence of str; element {index} is "
                    f"{type(element).__name__}."
                )

    warnings_state.tensor_with_adapt_messages = warn_if_adapt_messages_bypassed(
        input_controls, warnings_state.tensor_with_adapt_messages
    )
    tokenized = tokenizer(normalized, return_tensors="pt", padding=True)
    return tokenized["input_ids"], tokenized.get("attention_mask"), is_single
resolve_token_prompt(input_ids, attention_mask, *, input_controls, warnings_state)

Validate a token prompt (tokens only; design §4.3.3).

Parameters:

Name Type Description Default
input_ids Any

A 1-D/2-D torch.Tensor, a list[int], or a list[list[int]].

required
attention_mask Tensor | None

Optional mask, passed through unchanged.

required
input_controls 'list[InputControl]'

Input controls consulted for the bypass warning.

required
warnings_state PromptWarnings

Once-per-pipeline warning flags, updated in place.

required

Returns:

Type Description
tuple[Tensor, Tensor | None, bool]

tuple[input_ids, attention_mask, is_single].

Raises:

Type Description
ValueError

If a tensor is neither 1-D nor 2-D (E8), or nested lists are ragged (E9).

TypeError

If the value is not a token tensor or integer list (E10).

Source code in steerability/algorithms/core/utils/generation.py
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
def resolve_token_prompt(
        input_ids: Any,
        attention_mask: torch.Tensor | None,
        *,
        input_controls: "list[InputControl]",
        warnings_state: PromptWarnings,
) -> tuple[torch.Tensor, torch.Tensor | None, bool]:
    """Validate a token prompt (tokens only; design §4.3.3).

    Args:
        input_ids: A 1-D/2-D `torch.Tensor`, a `list[int]`, or a `list[list[int]]`.
        attention_mask: Optional mask, passed through unchanged.
        input_controls: Input controls consulted for the bypass warning.
        warnings_state: Once-per-pipeline warning flags, updated in place.

    Returns:
        tuple[input_ids, attention_mask, is_single].

    Raises:
        ValueError: If a tensor is neither 1-D nor 2-D (E8), or nested lists are ragged (E9).
        TypeError: If the value is not a token tensor or integer list (E10).
    """
    if isinstance(input_ids, torch.Tensor):
        if input_ids.ndim == 1:
            resolved, is_single = input_ids.unsqueeze(0), True
        elif input_ids.ndim == 2:
            resolved, is_single = input_ids, False
        else:
            raise ValueError(f"input_ids tensor must be 1-D or 2-D; got {input_ids.ndim}-D.")
    elif isinstance(input_ids, list) and input_ids and all(isinstance(x, int) for x in input_ids):
        resolved, is_single = torch.tensor([input_ids], dtype=torch.long), True
    elif (
        isinstance(input_ids, list) and input_ids
        and all(isinstance(row, list) and row and all(isinstance(x, int) for x in row) for row in input_ids)
    ):
        try:
            resolved = torch.tensor(input_ids, dtype=torch.long)
        except ValueError as exception:
            raise ValueError(
                "input_ids= nested lists must be rectangular (equal-length rows)."
            ) from exception
        is_single = False
    else:
        raise TypeError(
            f"input_ids= accepts a 1-D/2-D integer tensor, list[int], or list[list[int]]; got "
            f"{type(input_ids).__name__}. For text prompts use text= or positional input; for "
            "chat use messages=."
        )

    warnings_state.tensor_with_adapt_messages = warn_if_adapt_messages_bypassed(
        input_controls, warnings_state.tensor_with_adapt_messages
    )
    return resolved, attention_mask, is_single