Repository navigation
Epic: Fix Adapter Function Lifecycle & Consistency in Mellea #929
Description
Resolve systemic issues with how adapter functions are loaded, invoked, and configured across backends. We should finalize a design for the below points and then create issues for that finalized implementation.
Initial implementation of EmbeddedIntrinsicAdapters in: #881
Initial removal of OpenAI adapters: #543
-
Adapter Loading & Unloading
a. Clean up divergent control flow between EmbeddedAdapters and regular adapter function loading.
b. Fix bug where obtain_lora is always called during call_intrinsic when embedded_adapters=False, which masks the real error from users and conflicts with different loading methods.
c. Address that adapter loading/unloading is both backend-specific and adapter-type-specific — design a coherent abstraction for this. -
Model Option Handling
a. Fix adapter function rewriters overwriting model options unconditionally.
b. Decide and document how adapter functions should interact with model options.
c. There's a larger question of hierarchy with model options as well. Model options can technically be defined in all the following places: hf base model defaults in generation_config.json, adapter defaults in generation_config.json, io.yaml defaults, io.yaml values specified in the Mellea adapter function, mellea model options. -
Naming Consistency
a. Resolve whether adapter name must equal adapter.intrinsic_name or can differ (open issue).
b. Standardize usage of "adapter name", "adapter function name", and "qualified name" across the codebase.
c. refactor(intrinsics): decouple capability registry from catalog entry names (Epic #929 Phase 0) #1186 Decouple the capability registry from catalog entry names — Phase 0 follow-up. Therole→capabilityrename is merged in feat(intrinsics): introduce Adapter/Identity/IOContract/WeightsBinding scaffolding (Epic #929 Phase 0) #1134 (PR feat(intrinsics): introduce Adapter/Identity/IOContract/WeightsBinding scaffolding (Epic #929 Phase 0) #1158); the catalog-side decoupling is next in sequence once fix(intrinsics): pin catalogue entries to HF revision SHAs + deduplicate requirement_check (#1135) #1157 (fix(intrinsics): pin catalogue entries to HF revision SHAs + deduplicate requirement_check entries (Epic #929 Phase 0) #1135) and feat(intrinsics): introduce Adapter/Identity/IOContract/WeightsBinding scaffolding (Epic #929 Phase 0) #1158 (feat(intrinsics): introduce Adapter/Identity/IOContract/WeightsBinding scaffolding (Epic #929 Phase 0) #1134) merge.
d. fix(adapters): correct IntriniscsCatalogEntry class name typo (Epic #929 Naming) #1268 FixIntriniscsCatalogEntryclass name misspelling (Intriniscs → Intrinsics) — mechanical rename across 5 files; do after chore(terminology): adopt agreed Granite Switch / Mellea glossary (#1192) #1256 and refactor(adapters): decouple KNOWN_CAPABILITIES from catalog entry names (#1186) #1266 merge. -
Output Parsing & Generic Adapter Function Contracts
a. Address the problem where top-level call_intrinsics helpers assume a single output structure (e.g., result_json["answerability"] vs result_json["answerability_likelihood"]). We likely need to work with the Granite Switch team here to set common assumptions.
b. Determine whether all adapters of a given type must conform to a standard output schema (e.g., a single output field, required keys) or whether parsing should be adapter-specific.
c. This also encompasses "versioning" of adapter functions. The same adapter function may be updated / changed to have a different expected output format and our top-level call_intrinsic functions only allow one version. -
OpenAI Backend Support
a. Add OpenAIAdapters back — requires discussion on the logic for pulling/registering these. EmbeddedIntrinsicAdapters should technically inherit from these. -
Cleanup
a. Remove or repurpose the catalog. We shouldn't mandate all adapter functions be part of the known catalog.
Settled design decisions
- Adapter API: one lifecycle, or two shapes? #1486 — "Adapter API: one lifecycle, or two shapes?" (closed as resolved
2026-08-11). Outcome: neither. One shape, two jobs, varying on different axes —
request reformatting comes fromio_contract(varies by capability, identical
across backends), activation goes on the binding asapply_activation(varies by
deployment).Adapterkeeps its three fields; nothing new is added.
render_controlsandset_request_adapterhave no job left and are removed in
feat(backends): EmbeddedBinding implements apply_activation (Granite Switch path); remove render_controls + set_request_adapter (Epic #929 Phase 2) #1142. Discharged into refactor(intrinsics): resolve the adapter's output contract from the adapter, not a parallel argument (Epic #929 Phase 2) #1516 (contract axis) and a rescoped feat(backends): EmbeddedBinding implements apply_activation (Granite Switch path); remove render_controls + set_request_adapter (Epic #929 Phase 2) #1142
(activation axis) — independent axes, so both can proceed in parallel. add support for granite-switch / embedded adapters on our huggingface backend #1018 is
the acceptance test. This supersedes item 5a's "EmbeddedIntrinsicAdapters should
technically inherit from these" — the answer is composition plus one binding per
deployment, not an inheritance chain. - Span and metric naming is fixed and not up for reinvention.
adapter_function
parent,adapter_function.<phase>children,mellea.adapter_function.*attributes
and instruments, content gated onMELLEA_TRACES_CONTENT. Established by refactor(backends): AdapterMixin verb rename/narrow + resolve_model_options + IntrinsicMetricsPlugin (Epic #929 Phase 2) #1140 /
PR refactor(backends)!: narrow AdapterMixin verbs, centralize option resolution, add AdapterFunctionMetricsPlugin skeleton #1422, documented indocs/dev/adapter_observability.md. Several issues in this
epic previously specified an inventedintrinsic.*/MELLEA_TRACE_CONTENTscheme
that never existed in the codebase; corrected across feat(backends): LocalFileBinding implements verbs (PEFT/aLoRA path) + from_catalog() (Epic #929 Phase 2) #1141, feat(backends): EmbeddedBinding implements apply_activation (Granite Switch path); remove render_controls + set_request_adapter (Epic #929 Phase 2) #1142, refactor(intrinsics): remove deprecation shims; rewrite intrinsics_and_adapters.md; write 3 tutorials (Epic #929 Phase 4) #1144 and feat(telemetry): add complete adapter-function lifecycle observability #1466
on 2026-08-11. - Spans are produced by plugins, never inline in
mellea/backends/. The source
guidance is sufficient; docs(telemetry): document the hook/plugin span-production rule and enforce it (Epic #929) #1464 was intentionally closed after PR docs(telemetry): document hook/plugin span-production rule and enforce it #1545 review rather
than adding a standalone import guard. - design: adapter output-schema versioning (deferred from #929) #1111 removed from formal tracking (2026-09-03). Team decided output-schema
versioning isn't needed now; unlinked as a sub-issue of this epic, left open as
standalone backlog. See design: adapter output-schema versioning (deferred from #929) #1111 for the design questions and trigger conditions for
revisiting.
Phase Tracker
| Phase | Issue | Title | Status | Depends on |
|---|---|---|---|---|
| 0 | #1186 | Decouple KNOWN_CAPABILITIES from catalog names | ✅ Merged | — |
| 0 | #1135 | Catalogue revision pinning + deduplication | ✅ Merged | — |
| 0 | #1134 | Scaffolding: Adapter / Identity / IOContract / WeightsBinding | ✅ Merged | — |
| 0 | #1192 | Terminology sweep (docs/docs + backends) | ✅ Merged | — |
| 1 | #1136 | Internal shims + call_intrinsic rewrite |
✅ Merged (PR #1269) | — |
| 1 | #1137 | rag.py whole-file migration |
✅ Merged (PR #1321) | #1136 |
| 1 | #1138 | requirement_check migration |
✅ Merged (PR #1320) | #1136 |
| 1 | #1139 | guardian.py migration (behavioural) |
✅ Merged (PR #1323) | #1136 |
| 1 | #1332 | guardian.py IOContract subclasses + Adapter constants |
✅ Merged (PR #1357) | #1139, #1137 |
| 2 | #1140 | AdapterMixin verb narrow + resolve_model_options + AdapterFunctionMetricsPlugin |
✅ Merged (PR #1422) | Phase 1 |
| 2 | #1141 | LocalFileBinding verbs (PEFT / aLoRA path) + from_catalog() |
✅ Merged (PR #1454, 2026-08-17) | #1140 |
| 2 | #1142 | EmbeddedBinding implements apply_activation; remove render_controls + set_request_adapter |
✅ Merged (PR #1559, 2026-08-26) | #1134, #1140 |
| 2 | #1516 | Resolve the output contract from the adapter, not a parallel argument | ✅ Merged (PR #1556, 2026-08-25) | — |
| 2 | #1465 | Route intrinsic generation through adapter_scope; fix lock reentrancy |
✅ Merged (PR #1555, 2026-08-25) | #1141 |
| 2 | #1560 | Wire real adapter_function_invocation_complete outcome for Embedded activation |
🔄 PR #1609 approved, finishing CI/merge queue | #1465 |
| cross-cutting | #1464 | Document + enforce the hook/plugin span-production rule | ✅ Closed — intentionally dropped after PR #1545 review; source guidance is sufficient | — |
| 2 | #1528 | release() leaves the adapter registered — and is a binding reusable after release() at all? |
✅ Merged (PR #1554, 2026-08-24) | — |
| 2 | #1561 | IntrinsicAdapter.__init__ sets Identity.capability from the raw catalogue name, not effective_capability |
🗑️ Closed as duplicate of #1563 (2026-08-21) | — |
| 2 | #1562 | resolve_adapter() registers into _added_adapters outside _generation_lock |
🔄 PR #1607 approved, finishing CI/merge queue | #1465 |
| 2 | #1563 | Adapter shim Identity uses catalog name instead of effective_capability, causing spurious KNOWN_CAPABILITIES warnings |
✅ Merged (PR #1580, 2026-08-25) | — |
| 2 | #1575 | OpenAIBackend: user-supplied model in model_options collides with the hardcoded model kwarg |
✅ Merged (PR #1578, 2026-08-25) | — |
| 3 | #1018 | EmbeddedBinding × LocalHFBackend — acceptance test for #1486's shape | ✅ Merged (PR #1593, 2026-09-02) | #1142 |
| 2+ | #1574 | Real-model GPU e2e for the intrinsic HF path (adapter_scope routing) | 🔄 PR #1608 approved, finishing CI/merge queue | #1465 |
| cleanup | #1268 | Fix IntriniscsCatalogEntry class name typo |
✅ Merged (PR #1370) | — |
| cleanup | #1279 | Terminology prose sweep (docs/examples/ + docstrings) |
✅ Merged (PR #1322) | — |
| cleanup | #385 | Fix broken aLora example | ✅ Merged (PR #1557, 2026-08-24) | #1141 |
| cleanup | #1338 | Remove deprecated check_context_relevance and its adapter |
✅ Merged (PR #1579, 2026-08-25) | — |
| cleanup | #1412 | Promote _DictContract to shared adapters module; collapse guardian.py's duplicate factuality contracts |
✅ Merged (PR #1428) | — |
| cleanup | #1413 | Document policy_guardrails exception-type change (ValueError → AdapterSchemaMismatchError) |
✅ Merged (PR #1427) | — |
| 4 (final) | #1144 | Build composed-Adapter-direct backend support, then remove deprecation shims |
🏗️ In progress — spec rewritten 2026-09-03 (real scope: backend build, not just deletion; see issue for full detail). Two stacked PRs: PR1 additive (backend + docs + tutorials + CLI template + tests), PR2 deletion (shim removal, stacked on PR1) | #1141, #1142, #1516, #1465, #1018 (all merged) |
| deferred | #1358 | validate() should surface parse errors as a third outcome, not raise |
✅ Merged (PR #1591, 2026-08-27) | #1516 |
| — | #1611 | IOContract mismatches record success in embedded invocation-complete outcome |
⬜ New — surfaced during #1560/PR #1609, filed as a separate follow-on | #1560 |
Statuses and the "Depends on" column were reconciled against live issue, pull-request, and formal-dependency state on 2026-09-03. #1560, #1562, and #1574 all have approved PRs (#1609, #1607, #1608) finishing CI/merge queue — no code work left, just merge. #1111 has been unlinked from this epic (see Settled design decisions) and no longer appears in this tracker. #1144 is now the epic's only remaining active item — its scope was corrected today after research showed neither backend accepts a composed Adapter directly yet, so it's genuinely the epic's last unbuilt piece, not cleanup.
"⬜ Open, unclaimed" means no PR exists yet, not that the issue is unassigned.
Current status (reconciled 2026-09-03)
#1018 is merged. #1560, #1562, and #1574 are approved and finishing CI/merge queue — nothing left to do but merge. #1144 is now the epic's sole remaining active work: rewritten with a full stacked-PR spec (PR1 builds the composed-Adapter-direct path both backends currently lack, plus tests/docs/tutorials/CLI-template updates; PR2, stacked on PR1, deletes the three deprecated shim classes once nothing references them). #1111 removed from formal tracking, left open standalone. #1466 was already removed from formal tracking (2026-08-27, confirmed unlinked both directions) and isn't part of this epic.
Suggested order
- Merge fix(backends): fire adapter_function_invocation_complete for embedded adapter calls #1609, fix(backends): serialize resolve_adapter() registration under the activation lock #1607, test(backends): add real-model GPU e2e for intrinsic adapter_scope routing #1608 (all approved, finishing CI).
- Execute refactor(intrinsics): remove deprecation shims; rewrite intrinsics_and_adapters.md; write 3 tutorials (Epic #929 Phase 4) #1144's PR1 (additive), then PR2 (deletion, stacked) — see refactor(intrinsics): remove deprecation shims; rewrite intrinsics_and_adapters.md; write 3 tutorials (Epic #929 Phase 4) #1144 for the full spec.
- Once refactor(intrinsics): remove deprecation shims; rewrite intrinsics_and_adapters.md; write 3 tutorials (Epic #929 Phase 4) #1144/PR2 merges, this epic's numbered scope is structurally complete; close Epic: Fix Adapter Function Lifecycle & Consistency in Mellea #929.
Activity
jakelorocco commentedon May 6, 2026
requirement_checkadapters in our code for automatically utilizing requirement check adapters when present for requirements. The new design should account for this (and perhaps allow the intrinsic that ultimately gets used to be configurable). The changes from this PR should include all the spots that are necessary to evaluate these hard-coded values: https://github.com/generative-computing/mellea/pull/1008/changes.planetf1 commentedon May 7, 2026
Note from PR #1028 review: PR #1028 (normalize intrinsics interfaces) adds a new context-mutation path in the guardian intrinsics — both
factuality_detectionandfactuality_correctionnow rewind and re-attach documents to the last assistant message before callingcall_intrinsic. This path will need to be accounted for in the lifecycle refactor here; specifically, the rewind logic operates oncontext.previous_nodeand re-wraps the last turn, which could interact with any changes to how turns are structured during adapter loading/unloading.docs: add diagrams to adapter design proposal (generative-computing#929)
docs: replace misaligned ASCII reality diagram with Mermaid (generati…
docs: replace 'lands' phrasing with specific verbs (generative-comput…
docs: address first round of review comments (generative-computing#929)
docs: cite TestBasedEval and BenchDrift for qualitative tests (genera…
planetf1 commentedon May 7, 2026
Aiming to summarise / explain the current setup, issues, and what we want to achieve
Early version -> https://github.com/planetf1/mellea/blob/docs/issue-929-adapter-design-proposal/docs/dev/issue-929-adapter-design-proposal.md -- still checking for correctness. Hoping to get this right up-front, then the implementation should be easy ;-)
Ok to check in as a PR if useful
docs: second round review edits (generative-computing#929)
docs: improve progressive read; expand backend matrix (generative-com…
111 remaining items
feat(backends): EmbeddedBinding implements apply_activation (Granite …
planetf1 commentedon Sep 2, 2026
Status update (2026-09-02)
In progress (Iteration 11, @planetf1): #1560 (embedded invocation-complete telemetry), #1562 (resolve_adapter lock race), #1574 (GPU e2e for intrinsic PEFT path). Independent, no file overlap, running in parallel.
Then left:
Epic's numbered scope closes once #1144 lands.
feat(backends): accept composed Adapter directly (Epic generative-com…
fix(adapters): address code-review findings on the aLoRA activation g…
fix(adapters): raise or fall back when an aLoRA cannot activate (gene…
fix(adapters): raise or fall back when an aLoRA cannot activate (gene…
fix(adapters): raise or fall back when an aLoRA cannot activate (gene…
fix(adapters): raise or fall back when an aLoRA cannot activate (gene…