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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions docs/docs/integrations/openai.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,7 @@ backend = OpenAIBackend(
)

# Discover and register a single adapter from the model's Hugging Face repo —
# this composes an Adapter (Identity + IOContract + EmbeddedBinding) rather
# than returning the deprecated EmbeddedIntrinsicAdapter shim.
# this composes an Adapter (Identity + IOContract + EmbeddedBinding).
backend.register_embedded_adapter_model(
IBM_GRANITE_SWITCH_4_1_3B_PREVIEW.hf_model_name,
intrinsic_name="answerability",
Expand Down
8 changes: 4 additions & 4 deletions docs/docs/reference/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -572,10 +572,10 @@ runtime or uses adapter functions embedded in a local [Granite Switch](#granite-
checkpoint with `load_embedded_adapters=True`. `OpenAIBackend` also supports
embedded adapter functions when backed by a Granite Switch deployment.

> **Note:** The Python symbol `Intrinsic` (and related classes such as `IntrinsicAdapter`)
> will be renamed to `AdapterFunction` / `Adapter` in a future phase of Epic #929
> (#1136). Prefer the term **adapter function** in prose and documentation; use `Intrinsic`
> only when referencing the current Python API directly.
> **Note:** The Python symbol `Intrinsic` will be renamed to `AdapterFunction`
> in a future phase of Epic #929 (#1136). Prefer the term **adapter function**
> in prose and documentation; use `Intrinsic` only when referencing the current
> Python API directly.

See: [Adapter Functions](../advanced/intrinsics.md)

Expand Down
4 changes: 2 additions & 2 deletions docs/docs/tutorials/07-custom-adapter-function.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: "Compose your own trained LoRA/aLoRA adapter into Mellea without a

This tutorial walks through registering a custom, non-catalog adapter
function by composing an `Adapter` directly — the replacement for the
deprecated `CustomIntrinsicAdapter` shim (Epic #929, issue #1144).
removed `CustomIntrinsicAdapter` shim (Epic #929, issue #1144).

By the end you will have covered:

Expand Down Expand Up @@ -137,7 +137,7 @@ result = m.instruct(

## What replaced the old approach

The deprecated `CustomIntrinsicAdapter` shim did two things under the hood
The removed `CustomIntrinsicAdapter` shim did two things under the hood
that this tutorial's composed `Adapter` replaces without a class of its own:

1. **Adapter registration** — `LocalFileBinding` already accepts an arbitrary
Expand Down
3 changes: 1 addition & 2 deletions docs/examples/granite-switch/manual_adapter_loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
the model repo at init), this example shows how to create an OpenAIBackend with
`load_embedded_adapters=False` and then manually load individual adapters using
`register_embedded_adapter_model(intrinsic_name=...)`, which composes an
`Adapter` (Identity + IOContract + EmbeddedBinding) instead of the deprecated
`EmbeddedIntrinsicAdapter` shim.
`Adapter` (Identity + IOContract + EmbeddedBinding).

This is useful when:
- You only need a subset of the model's embedded adapters.
Expand Down
4 changes: 0 additions & 4 deletions mellea/backends/adapters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
AdapterInput,
AdapterMixin,
AdapterType,
EmbeddedIntrinsicAdapter,
IntrinsicAdapter,
LocalHFAdapter,
fetch_intrinsic_metadata,
get_adapter_for_intrinsic,
Expand All @@ -39,10 +37,8 @@
"AloraActivationError",
"EmbeddedActivationRequest",
"EmbeddedBinding",
"EmbeddedIntrinsicAdapter",
"IOContract",
"Identity",
"IntrinsicAdapter",
"LocalFileBinding",
"LocalHFAdapter",
"ServerMediatedBinding",
Expand Down
38 changes: 28 additions & 10 deletions mellea/backends/adapters/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
The existing :class:`~mellea.backends.adapters.adapter.Adapter` ABC in
`adapter.py` is not modified here. This module introduces a new
`Adapter` *dataclass* that is re-exported from
`mellea.backends.adapters`. Both coexist until shim removal in 4.1.
`mellea.backends.adapters`. Both coexist for now.
The old ABC is not part of the public `__init__.py` surface, so there is
no namespace collision on the public API.
"""
Expand Down Expand Up @@ -691,6 +691,16 @@ def hold_prepared(self, backend: "AdapterMixin") -> Iterator[None]:
def activate(self) -> None:
"""Selects already-loaded adapter weights for generation.

Resilient to the weights having been dropped from the backend's PEFT
model since `prepare()`: `prepare()` injects the weights once, but an
`unload_peft_adapter()` call (e.g. to free GPU memory, or as a test
teardown) deletes them from the PEFT model while leaving this binding's
registration intact. Re-injecting them here — rather than treating
`prepare()` as a one-time guarantee — lets a composed `Adapter` be
unloaded and later re-used on the same backend without a hard failure
(the resilience the removed `IntrinsicAdapter` shim gave by re-loading
on demand).

Raises:
RuntimeError: `prepare()` was not called first, or called but did
not complete (registered with the backend but the weights
Expand All @@ -706,7 +716,19 @@ def activate(self) -> None:
raise RuntimeError(
"LocalFileBinding.activate() requires prepare() to be called first."
)
backend.activate_peft_adapter(self.qualified_name)
try:
backend.activate_peft_adapter(self.qualified_name)
except ValueError:
# The weights were dropped from the PEFT model since prepare()
# (an intervening unload_peft_adapter), so set_adapter() cannot
# find the name. The registration in `_added_adapters` survives
# an unload, so load_peft_adapter() re-injects it; retry once.
# Both verbs mutate PEFT model state the activation lock already
# held here guards, so no new lock is taken — re-loading under
# `_lifecycle_lock` (as prepare() does) would invert the adapter
# lock order against a concurrent release().
backend.load_peft_adapter(self.qualified_name)
backend.activate_peft_adapter(self.qualified_name)
self._active = True

def deactivate(self) -> None:
Expand Down Expand Up @@ -1129,11 +1151,7 @@ class Adapter:
# (registration and the verbs key on the binding's `qualified_name`;
# `_find_adapter` scans on the identity) and both return `None` on a miss,
# so a disagreement surfaces as "adapter not found" far from its cause. It
# could not be enforced here because the deprecated shims carry a
# `_ShimWeightsBinding` with no `name`/`adapter_type` to compare at all
# (their identity tracks the configured name/type) — that no longer
# blocks the LocalFile/PEFT reality now that the shims retire in #1144, so
# `LocalHFBackend.add_adapter` enforces it there instead, at registration
# time. `EmbeddedBinding` has no `name`/`adapter_type` of its own, so the
# Embedded/Granite Switch reality still has nothing to cross-check
# against.
# is enforced not here but in `LocalHFBackend.add_adapter`, at registration
# time, so a construction that never reaches a backend isn't rejected.
# `EmbeddedBinding` has no `name`/`adapter_type` of its own, so the
# Embedded/Granite Switch reality has nothing to cross-check against.
Loading
Loading