Skip to content

Epic: Fix Adapter Function Lifecycle & Consistency in Mellea #929

Description

@jakelorocco

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

  1. 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.

  2. 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.

  3. 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. The rolecapability rename 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 Fix IntriniscsCatalogEntry class 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.

  4. 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.

  5. OpenAI Backend Support
    a. Add OpenAIAdapters back — requires discussion on the logic for pulling/registering these. EmbeddedIntrinsicAdapters should technically inherit from these.

  6. Cleanup
    a. Remove or repurpose the catalog. We shouldn't mandate all adapter functions be part of the known catalog.

Settled design decisions

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 🔄 PR #1559 in review; rebase required #1134, #1140
2 #1516 Resolve the output contract from the adapter, not a parallel argument 🔄 PR #1556 in review
2 #1465 Route intrinsic generation through adapter_scope; fix lock reentrancy 🔄 PR #1555 in review #1141
2 #1466 Emit adapter-function spans from a tracing plugin 🔄 PR #1558 approved, held for telemetry review; rebase required. Scoped to lifecycle (prepare/activate/deactivate) spans only #1465 (generate/parse spans only, not started)
2 #1577 Ensure adapter-function span completion drains _in_flight_spans on telemetry exceptions ⬜ Open, unclaimed — robustness follow-up to #1558; not a blocker for that PR PR #1558 (new lifecycle path only)
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 ⬜ Open, unclaimed — found during #1465 review; suggested fix reuses #1465's reentrant lock #1465
2 #1563 Adapter shim Identity uses catalog name instead of effective_capability, causing spurious KNOWN_CAPABILITIES warnings 🔄 PR #1580 in review. Supersedes closed #1561 (also covers EmbeddedIntrinsicAdapter)
2 #1575 OpenAIBackend: user-supplied model in model_options collides with the hardcoded model kwarg 🔄 PR #1578 in review; rejects the option as decided on 2026-08-20
2+ #1018 EmbeddedBinding × LocalHFBackend — acceptance test for #1486's shape ⬜ Open, unclaimed — waiting on #1142 to merge #1140, #1142
2+ #1574 Real-model GPU e2e for the intrinsic HF path (adapter_scope routing) ⬜ Open, unclaimed — waiting on #1465 to merge (PR #1555 open) #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 🔄 PR #1579 in review
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 (ValueErrorAdapterSchemaMismatchError) ✅ Merged (PR #1427)
4 #1144 Remove deprecation shims + rewrite tutorials ⬜ Pending — last in the chain All of Phase 2: #1141, #1142, #1516, #1465, #1466, #1018
deferred #1111 Adapter output-schema versioning design ⬜ Needs design discussion first #1134
deferred #1358 validate() should surface parse errors as a third outcome, not raise ⬜ Open — author's own proposal defers this until Phase 2/IOContract consolidation is further along #1516

Statuses and the "Depends on" column were reconciled against issue state, open PRs, and the
formal GitHub dependency graph on 2026-08-24. PRs #1554 (#1528) and #1557 (#385) merged today;
#1555/#1556/#1559 remain in review, #1558 is approved but deliberately held for telemetry review,
and #1578/#1579/#1580 are the new review PRs for #1575/#1338/#1563. #1577 was added as a
formal epic child and tracker row; it is a non-blocking telemetry-hardening follow-up to #1558.
"⬜ Open, unclaimed" means no PR exists yet, not that the issue is unassigned.

Current batch (started 2026-08-18)

#1528 and #385 merged on 2026-08-24. #1555 (#1465), #1556 (#1516), and #1559
(#1142) remain in review. #1558 is approved but held for telemetry review and needs a
rebase before merging; it delivers only #1466's lifecycle-span slice. Review work also
produced #1562, #1563, #1575, and #1577. The first is blocked by #1465; the latter three
now have their own tracker rows, and #1577 is not a blocker for the current batch.

Suggested order

  1. feat(backends): LocalFileBinding implements verbs (PEFT/aLoRA path) + from_catalog() (Epic #929 Phase 2) #1141 / PR feat(backends): LocalFileBinding implements verbs (PEFT/aLoRA path) + from_catalog() (Epic #929 Phase 2) #1454 — merged 2026-08-17.
  2. refactor(intrinsics): resolve the adapter's output contract from the adapter, not a parallel argument (Epic #929 Phase 2) #1516, feat(backends): EmbeddedBinding implements apply_activation (Granite Switch path); remove render_controls + set_request_adapter (Epic #929 Phase 2) #1142, refactor(backends): route intrinsic generation through adapter_scope (Epic #929 Phase 2) #1465, and feat(telemetry): emit adapter-function spans from a tracing plugin (Epic #929 Phase 2) #1466 (lifecycle spans only) — active review work;
    feat(telemetry): emit adapter-function prepare/activate/deactivate spans from a tracing plugin #1558 is held for telemetry review. OpenAIBackend: user-supplied model in model_options collides with the hardcoded model kwarg (follow-up to #1142) #1575, Remove deprecated check_context_relevance and context_relevance adapter #1338, and Adapter shim Identity uses catalog name instead of effective_capability, causing spurious KNOWN_CAPABILITIES warnings #1563 are independent
    review PRs (fix(backends): reject OpenAI model option overrides #1578/fix(adapter-functions): remove deprecated context relevance intrinsic #1579/fix(adapters): use effective capabilities in shim identities #1580).
    feat(telemetry): emit adapter-function spans from a tracing plugin (Epic #929 Phase 2) #1466's generate/parse spans still wait on refactor(backends): route intrinsic generation through adapter_scope (Epic #929 Phase 2) #1465 and are explicitly out of
    scope for this batch.
  3. add support for granite-switch / embedded adapters on our huggingface backend #1018 — the acceptance test that Adapter API: one lifecycle, or two shapes? #1486's shape actually holds. Blocked until
    feat(backends): EmbeddedBinding implements apply_activation (Granite Switch path); remove render_controls + set_request_adapter (Epic #929 Phase 2) #1142 merges (not just opens as a PR).
  4. validate should surface parse errors as a third outcome rather than propagating exceptions #1358 — blocked until refactor(intrinsics): resolve the adapter's output contract from the adapter, not a parallel argument (Epic #929 Phase 2) #1516 merges.
  5. refactor(intrinsics): remove deprecation shims; rewrite intrinsics_and_adapters.md; write 3 tutorials (Epic #929 Phase 4) #1144 last (needs all of Phase 2 merged: 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): resolve the adapter's output contract from the adapter, not a parallel argument (Epic #929 Phase 2) #1516, refactor(backends): route intrinsic generation through adapter_scope (Epic #929 Phase 2) #1465,
    feat(telemetry): emit adapter-function spans from a tracing plugin (Epic #929 Phase 2) #1466 in full, add support for granite-switch / embedded adapters on our huggingface backend #1018).
  6. fix(telemetry): adapter_function span completion can strand _in_flight_spans entries #1577 — can be prepared as a stacked telemetry-hardening follow-up to feat(telemetry): emit adapter-function prepare/activate/deactivate spans from a tracing plugin #1558;
    it is not on the critical path.
  7. design: adapter output-schema versioning (deferred from #929) #1111 — independent deferred design work; no implementation starts until the
    output-schema-versioning decision is recorded.

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 requestepicHigh level Epicp1High: important bugs (workaround exists) or high-value core features. Do soon, not on fire.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions