feat(backends): support embedded adapters on LocalHFBackend - #1593
feat(backends): support embedded adapters on LocalHFBackend#1593planetf1 wants to merge 6 commits into
Conversation
AngeloDanducci
left a comment
There was a problem hiding this comment.
Generally LGTM, one small thing to change WRT the dependencies.
| # granite-switch 0.1.0 declares transformers<5.10.0. Mellea's local Granite | ||
| # Switch e2e passes on 5.10.2; retain Mellea's tested HF range until upstream | ||
| # publishes widened Granite Switch metadata. | ||
| override-dependencies = ["transformers>5.5.0,<6.0.0"] |
There was a problem hiding this comment.
I think [tool.uv] override-dependencies is only an uv workspace configuration — it is not part of [project] requires-dist and is never written into the built wheel/sdist. It only affects resolution inside this repo.
Should probably be moved to [project] somewhere.
There was a problem hiding this comment.
You're right that override-dependencies never makes it into the published package — that's a [tool.uv] setting, not a [project] one, so it only affects resolution when someone builds this repo with uv (our own dev environment, CI, and the lockfile). It's invisible to anyone installing the built wheel with plain pip.
Why not move it to [project]: there's nowhere to move it to. [project.dependencies] can only add version specifiers for mellea's own dependencies — it has no way to override a different package's declared constraint. Since the thing being overridden here is granite-switch's own transformers cap, not ours, [project] simply can't express it.
What it actually changes, for us: granite-switch 0.1.0 declares transformers<5.10.0. We've tested and confirmed 5.10.2 works fine with it. Without the override, uv would obey granite-switch's cap and pick something older than 5.10.0 for our own dev/test runs. The override just tells uv "ignore that cap, use our tested range instead" — purely for our own resolver.
What it means for someone installing mellea with pip: nothing breaks. Mellea's own dependency line already says transformers>5.5.0,<6.0.0, and granite-switch says <5.10.0. Those two ranges overlap (anything between 5.5.0 and 5.10.0), so pip can satisfy both without any conflict. The only difference is pip will pick something in that overlap — not 5.10.2, since the override that would push it there doesn't exist outside our repo. So a pip install still works, it just won't necessarily end up on the exact version we've tested against.
Why this is temporary: granite-switch's <5.10.0 cap looks out of date — nothing we've seen suggests 5.10.2 is actually a problem, and our e2e run confirms it isn't. I haven't raised this with granite-switch upstream yet (was travelling/out at the end of last week), but that's the plan: get their cap widened, and once that ships, this override can come out entirely.
Assisted-by: Codex Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
Assisted-by: Codex Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
Assisted-by: Codex Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
Assisted-by: Codex Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
Assisted-by: Codex Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
Assisted-by: Codex Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
Rebase retestedRebased onto
|
Pull Request
Issue
Fixes #1018
Description
Before this change, a Mellea user with a Granite Switch checkpoint could use its
embedded adapter functions only through a vLLM deployment and
OpenAIBackend.They could not point
LocalHFBackendat the checkpoint and use the existingadapter-function helpers locally.
After installing
mellea[hf], a user can constructLocalHFBackend(..., load_embedded_adapters=True)around a local Granite Switchcheckpoint and call the same adapter-function helpers. Mellea discovers the
embedded functions, renders the selected control token through the checkpoint's
chat template, and parses the result. No separate adapter weights need to be
downloaded, loaded, or activated through PEFT.
Existing LocalHF runtime LoRA/aLoRA behaviour is unchanged: the Granite Switch
dependency and registration import run only when
load_embedded_adapters=Trueis selected.What changes
LocalHFBackend(load_embedded_adapters=True)discovers embedded adapter functions from a local checkpoint or Hugging Face source.EmbeddedBinding.apply_activation()after request rewriting. The resultingadapter_nameis forwarded intotokenizer.apply_chat_template().adapter_scope().mellea[hf]local install path and include a runnable local example.Granite Switch dependency compatibility
The local checkpoint path installs through
mellea[hf], which importsthe Granite Switch HF registration package only when embedded adapter functions
are requested. Granite Switch 0.1.0 currently declares a Transformers range
that excludes Mellea's resolved version, even though the consolidated local 3B
e2e passes on that version. Mellea therefore records an explicit resolver
override and emits a one-time warning while the installed Granite Switch
metadata still excludes the resolved Transformers version. The warning
automatically disappears when Granite Switch publishes widened metadata.
Current runtime warning:
Follow-up: validate the wider range with the Granite Switch maintainers before
the next release.
Effect
Users can run adapter functions against a local Granite Switch checkpoint through
LocalHFBackend. Only adapter functions listed in that checkpoint'sadapter_index.jsonare available; the existing runtime LoRA/aLoRA path is unchanged.Deliberately out of scope
EmbeddedIntrinsicAdaptercompatibility shim withdirect composed
Adapter(..., EmbeddedBinding(...))execution. That publicmigration is documented for refactor(intrinsics): remove deprecation shims; rewrite intrinsics_and_adapters.md; write 3 tutorials (Epic #929 Phase 4) #1144.
CICD=1.Testing
uv run pytest test/backends/test_huggingface_unit.py -q— 98 passeduv run mypy mellea/backends/huggingface.py mellea/backends/adapters/adapter.py test/backends/test_huggingface_unit.pyuv run ruff checkanduv run ruff format --checkon changed Python filesnpx markdownlint-cli2 "docs/docs/advanced/intrinsics.md"uv run pytest test/backends/test_huggingface_embedded.py -q -rs— real3B LocalHF e2e passed on Apple Silicon (1 passed, 30.93 s)
Same targeted e2e on a Linux GPU runner (1 passed, 60.18 s), including
the assertion that the Switch template changes when
adapter_nameis setuv sync --extra hffollowed by the new local example —returned
Answerability: answerableMarkdownlint plus API-doc build and 100% docstring-quality audit
uv run pytest test/ -m "not qualitative"— 4,130 passed, 1 failed. The unrelatedtest_matplotlib_agg_injectedtimed out while creating its isolated matplotlib environment; its requested targeted rerun passed.Tests added to the respective file if code was changed
New code has 100% coverage if code was added
Ensure existing tests and github automation passes (a maintainer will kick off the github automation when the rest of the PR is populated)
Attribution
Adding a new component, requirement, sampling strategy, or tool?
NOTE: Please ensure you have an issue that has been acknowledged by a core contributor and routed you to open a pull request against this repository. Otherwise, please open an issue before continuing with this pull request.