Skip to content

add support for granite-switch / embedded adapters on our huggingface backend #1018

Closed

Description

@jakelorocco

Parent epic: #929
Phase: 3 (scope research / acceptance criteria before implementation)
Depends on: #1142
Blocks: #1144

⚠️ Thinly specified — scope research required before starting.
The Granite Switch HF path has not been mapped against the new EmbeddedBinding API.
Scope research is now unblocked. Do not begin implementation until items 1–3 below are resolved and the implementer has read the
granite-switch HF examples
against the new binding interface.


Problem

EmbeddedBinding.apply_activation (implemented in #1142) teaches the OpenAI backend
how to activate an embedded adapter by writing chat_template_kwargs["adapter_name"]
into the outgoing request.

LocalHFBackend has no equivalent path. Loading and running a Granite Switch model
locally via the HF backend today requires the caller to replicate the activation logic
manually — nothing in LocalHFBackend knows how to route an EmbeddedBinding through
its generation path.

This means a user who has a Granite Switch checkpoint locally cannot use adapter functions
through the standard Adapter(weights=EmbeddedBinding.from_base_model(backend)) pattern —
the backend simply ignores the binding.

Scope

Out of scope

Research required before writing acceptance criteria

  1. Read granite-switch HF inference examples
    and map the activation field against LocalHFBackend's generation entry point.
  2. Confirm whether apply_activation as designed in feat(backends): EmbeddedBinding implements apply_activation (Granite Switch path); remove render_controls + set_request_adapter (Epic #929 Phase 2) #1142 produces the right request
    shape for HF local inference, or whether HF needs a different field name/location.
  3. Determine whether the existing EmbeddedIntrinsicAdapter code path in the OpenAI
    backend (pre-feat(backends): EmbeddedBinding implements apply_activation (Granite Switch path); remove render_controls + set_request_adapter (Epic #929 Phase 2) #1142) has any HF-equivalent that would need to be removed.

Once (1)–(3) are answered, replace this section with concrete acceptance criteria,
a test plan, and a breaking-changes note following the format of #1141 / #1142.

References

Activity

  1. added this to the Release 0.6.0 milestone on May 6, 2026
  2. added
    area/backendsProvider-specific work: Ollama, HF, LiteLLM, OpenAI, Bedrock, vLLM
    enhancementNew feature or request
    on May 20, 2026
  3. planetf1 commented on May 26, 2026

    @planetf1
    Contributor

    Closing as superseded by #1142 (feat(backends): EmbeddedBinding implements verbs — Granite Switch path + OTel spans), which is tracked as part of the adapter lifecycle epic #929. Will be addressed when Phase 2 of that epic lands.

  4. removed this from the Release 0.6.0 milestone on May 26, 2026
  5. jakelorocco commented on May 26, 2026

    @jakelorocco
    ContributorAuthor

    @planetf1, the linked issue (#1142) explicitly lists this issue as out of scope. We should ensure that this work does get done (even if it happens after the epic / major refactor).

  6. planetf1 commented on May 26, 2026

    @planetf1
    Contributor

    @jakelorocco — you're right. #1142 explicitly defers this; closing it as superseded was wrong. Reopening as a follow-on blocked on #1142.

  7. added
    p2Medium/low: minor bugs, niche features, polish, docs, tests, cleanup. Scoped, lower urgency.
    on Jun 18, 2026
  8. added
    area/adapter-functionsGranite adapter functions: framework and adaptiers including RAG, Guardian, Core
    on Jun 19, 2026
  9. planetf1 commented on Jun 19, 2026

    @planetf1
    Contributor

    Assessment: scope, sequencing, and what remains

    Researched this against the current codebase and the granite-switch repo to clarify what work is actually needed here.

    What Granite Switch embedded adapters are

    Granite Switch composes multiple adapter functions (answerability, query-rewrite, hallucination detection, etc.) into a single HF-compatible checkpoint. Adapters are activated via control tokens injected by the model's own chat template — there is no separate PEFT file to load at runtime and no set_adapter() call. This is the EmbeddedBinding / "Reality B" path in Epic #929's design.

    Current state

    OpenAIBackend already supports this fully (PR #881): load_embedded_adapters=True, and _generate_from_intrinsic injects chat_template_kwargs["adapter_name"] to activate the control token.

    LocalHFBackend does not. _generate_from_intrinsic (huggingface.py:594) raises:

    TypeError("LocalHFBackend only supports IntrinsicAdapters")
    

    There is no load_embedded_adapters flag, no chat_template_kwargs["adapter_name"] injection on the local generate path, and add_adapter is typed for LocalHFAdapter only.

    Relationship to Phase 2 (#1140, #1142)

    This issue is not covered by #1140 or #1142 — both explicitly list #1018 in their Out of scope sections. #1142 ports EmbeddedBinding through the new binding abstraction but only on the OpenAI path.

    #1018 is the distinct follow-on: wiring the (refactored) EmbeddedBinding and render_controls verb into LocalHFBackend. It depends on #1140 and #1142 and should land after both merge, before docs consolidation (Phase 4 / #1144).

    Scope of this issue

    1. Add load_embedded_adapters=True support to LocalHFBackend — mirror the OpenAI registration path in mellea/backends/adapters/_util.py; reuse EmbeddedIntrinsicAdapter.from_source/from_hub.
    2. Implement render_controls on LocalHFBackend: inject chat_template_kwargs["adapter_name"] into transformers.generate(); skip the PEFT load_adapter/set_adapter path and the obtain_lora call (Epic Epic: Fix Adapter Function Lifecycle & Consistency in Mellea #929 item 1.b).
    3. Route _generate_from_intrinsic (or the post-feat(backends): EmbeddedBinding implements apply_activation (Granite Switch path); remove render_controls + set_request_adapter (Epic #929 Phase 2) #1142 EmbeddedBinding.activate path) through this new path instead of raising TypeError.
    4. Run the existing IntrinsicsRewriter / IntrinsicsResultProcessor I/O transform (already used by the OpenAI path).
    5. Add a LocalHFBackend × EmbeddedBinding integration test (@integration, @hf, @slow) against a Granite Switch checkpoint.

    Out of scope: the OpenAI embedded path (#1142), the local PEFT/aLoRA LocalFileBinding path (#1141).

    Key files

    File Relevance
    mellea/backends/huggingface.py:509-594 _generate_from_intrinsic — where the TypeError lives
    mellea/backends/huggingface.py:1800 add_adapter — typed LocalHFAdapter only
    mellea/backends/openai.py:638-647 Reference implementation for embedded path
    mellea/backends/adapters/adapter.py:311 EmbeddedIntrinsicAdapter (already exists)
    mellea/backends/adapters/_core.py:195 EmbeddedBinding stub
    mellea/stdlib/components/intrinsic/_util.py:122-128 _uses_embedded_adapters registration hook to mirror

    Acceptance criteria

    • LocalHFBackend(load_embedded_adapters=True) registers embedded adapters from a Granite Switch source
    • Intrinsic call activates the correct control token via chat_template_kwargs["adapter_name"]; no PEFT load / obtain_lora on this path
    • LocalHFBackend × EmbeddedBinding integration test passes
    • Output parsed through IntrinsicsResultProcessor (shared with OpenAI path)
    • ruff / mypy clean

    Blocked by: #1140, #1142

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area/adapter-functionsGranite adapter functions: framework and adaptiers including RAG, Guardian, Corearea/backendsProvider-specific work: Ollama, HF, LiteLLM, OpenAI, Bedrock, vLLMenhancementNew feature or requestp2Medium/low: minor bugs, niche features, polish, docs, tests, cleanup. Scoped, lower urgency.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions