Repository navigation
UN-2896 [MISC] Deprecate and remove the LLMWhisperer V1 adapter #2260
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Deepak-Kesavan
wants to merge
12
commits into
main
Choose a base branch
from
UN-2896-remove-llmwhisperer-v1
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+469
−853
Open
Changes from 1 commit
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
fee6da2
UN-2896 [MISC] Deprecate and remove the LLMWhisperer V1 adapter
Deepak-Kesavan 4cecc1a
UN-2896 [FIX] Self-review: close the remaining deprecated-adapter paths
Deepak-Kesavan c7624ae
UN-2896 [FIX] Silence Sonar S117 on the migration's get_model calls
Deepak-Kesavan 954e692
Merge branch 'main' into UN-2896-remove-llmwhisperer-v1
harini-venkataraman 1a5d92c
UN-2896 [FIX] Don't re-validate unchanged defaults in set_default_triad
Deepak-Kesavan 56a08ac
UN-2896 [MISC] Correct the V2 adapter's env var docs
Deepak-Kesavan 110dabf
Merge remote-tracking branch 'origin/UN-2896-remove-llmwhisperer-v1' …
Deepak-Kesavan 8cde306
UN-2896 [MISC] Revert the V2 env var doc edits
Deepak-Kesavan 1aef6bc
UN-2896 [TEST] Cover the deprecated-adapter execution path
Deepak-Kesavan 2024cba
UN-2896 [MISC] Drop the set_default_triad deprecation guard
Deepak-Kesavan 1bc83c8
Merge remote-tracking branch 'origin/main' into UN-2896-remove-llmwhi…
Deepak-Kesavan 6296d43
Merge remote-tracking branch 'origin/main' into UN-2896-remove-llmwhi…
Deepak-Kesavan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next
Next commit
UN-2896 [MISC] Deprecate and remove the LLMWhisperer V1 adapter
Adds a single DEPRECATED_ADAPTERS registry that drives every guard, seeded with LLMWhisperer V1, and deletes the V1 adapter package it retires. Guards (adapter-type agnostic, so future deprecations are a one-line entry): - excluded from supported_adapters, so it cannot be picked for creation - POST /adapter/ and /test_adapters/ reject a deprecated adapter_id - profile manager rejects pointing a profile at one; existing profiles on a deprecated adapter stay editable in their other fields - platform-service rejects execution off the is_available column, which is every SDK adapter lookup's single choke point Backfill migration marks existing V1 instances unavailable across all orgs (0003 used .first(), which marked only one row per adapter). Removes the V1 package, its icon, its dead env vars (POLL_INTERVAL, MAX_POLLS, STATUS_RETRIES -- V2 uses WAIT_TIMEOUT/MAX_RETRIES/RETRY_*) and the workflow-execution plumbing that forwarded them into tool containers. Claude-Session: https://claude.ai/code/session_01DXuiGyUwXyU1EVQBeMHppe
- Loading branch information
commit fee6da2de99e74257acf4c6e6fa9cefd369e00db
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| """Registry of adapters that are no longer offered. | ||
|
|
||
| Adding an entry here is the whole deprecation: the adapter drops out of the | ||
| supported-adapter listing, creation of new instances is rejected, and profiles | ||
| can no longer be pointed at it. Existing instances keep rendering so users can | ||
| see what to migrate off. | ||
|
|
||
| ``platform-service`` gates execution on the ``is_available`` column instead of | ||
| this registry (it is a separate service with no access to Django app code), so | ||
| a new entry needs a data migration that marks the matching rows unavailable. | ||
| """ | ||
|
|
||
| from typing import Any | ||
|
|
||
| # adapter_id ("name|uuid", as stored on AdapterInstance) -> deprecation metadata | ||
| DEPRECATED_ADAPTERS: dict[str, dict[str, Any]] = { | ||
| "llmwhisperer|0a1647f0-f65f-410d-843b-3d979c78350e": { | ||
| "reason": ( | ||
| "LLMWhisperer V1 is retired. Please switch to the LLMWhisperer V2 " | ||
| "text extractor." | ||
| ), | ||
| "deprecated_date": "2026-08-31", | ||
| "replacement_adapter": "LLMWhisperer V2", | ||
| "adapter_name": "LLMWhisperer", | ||
| "adapter_type": "X2TEXT", | ||
| }, | ||
| } | ||
|
|
||
|
|
||
| def is_adapter_deprecated(adapter_id: str | None) -> bool: | ||
| """Whether ``adapter_id`` is a deprecated adapter.""" | ||
| return bool(adapter_id) and adapter_id in DEPRECATED_ADAPTERS | ||
|
|
||
|
|
||
| def get_deprecation_metadata(adapter_id: str | None) -> dict[str, Any] | None: | ||
| """Deprecation metadata for ``adapter_id``, or None if it is not deprecated.""" | ||
| if not adapter_id: | ||
| return None | ||
| metadata = DEPRECATED_ADAPTERS.get(adapter_id) | ||
| return dict(metadata) if metadata else None | ||
|
|
||
|
|
||
| def get_deprecation_message(adapter_id: str | None) -> str: | ||
| """User-facing reason ``adapter_id`` can no longer be used.""" | ||
| metadata = get_deprecation_metadata(adapter_id) | ||
| if not metadata: | ||
| return "This adapter has been deprecated and can no longer be used." | ||
| name = metadata.get("adapter_name") or "This adapter" | ||
| return f"{name} has been deprecated. {metadata['reason']}" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
backend/adapter_processor_v2/migrations/0007_deprecate_llmwhisperer_v1.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| # Generated by Django 4.2.30 on 2026-08-31 06:48 | ||
|
|
||
| import logging | ||
|
|
||
| from django.db import migrations | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| ADAPTER_ID = "llmwhisperer|0a1647f0-f65f-410d-843b-3d979c78350e" | ||
|
|
||
| # Frozen copy of the adapter_processor_v2.deprecated_adapters entry. Runtime | ||
| # behaviour reads the registry, so wording drifting from it changes nothing. | ||
| DEPRECATION_METADATA = { | ||
| "reason": ( | ||
| "LLMWhisperer V1 is retired. Please switch to the LLMWhisperer V2 " | ||
| "text extractor." | ||
| ), | ||
| "deprecated_date": "2026-08-31", | ||
| "replacement_adapter": "LLMWhisperer V2", | ||
| "adapter_name": "LLMWhisperer", | ||
| "adapter_type": "X2TEXT", | ||
| } | ||
|
|
||
|
|
||
| def mark_llmwhisperer_v1_deprecated(apps, schema_editor): | ||
| """Mark every LLMWhisperer V1 instance unavailable, across all orgs. | ||
|
|
||
| platform-service reads this column to reject execution, so a row missed | ||
| here would fail deep in the SDK instead of with the deprecation message. | ||
| """ | ||
| AdapterInstance = apps.get_model("adapter_processor_v2", "AdapterInstance") | ||
|
|
||
| updated = AdapterInstance.objects.filter(adapter_id=ADAPTER_ID).update( | ||
| is_available=False, deprecation_metadata=DEPRECATION_METADATA | ||
| ) | ||
| logger.info("Marked %s LLMWhisperer V1 adapter instance(s) as deprecated.", updated) | ||
|
|
||
|
|
||
| def reverse_deprecation(apps, schema_editor): | ||
| AdapterInstance = apps.get_model("adapter_processor_v2", "AdapterInstance") | ||
|
|
||
| updated = AdapterInstance.objects.filter(adapter_id=ADAPTER_ID).update( | ||
| is_available=True, deprecation_metadata=None | ||
| ) | ||
| logger.info("Reversed deprecation for %s LLMWhisperer V1 instance(s).", updated) | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
| dependencies = [ | ||
| ("adapter_processor_v2", "0006_adapterinstance_adapter_org_modified_idx"), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.RunPython(mark_llmwhisperer_v1_deprecated, reverse_deprecation), | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
backend/adapter_processor_v2/tests/test_deprecated_adapters.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| """Guards for the adapter deprecation registry (UN-2896). | ||
|
|
||
| Every entry in ``DEPRECATED_ADAPTERS`` must be absent from the SDK registry and | ||
| absent from the supported-adapter listing, so a deprecated adapter cannot be | ||
| re-registered or offered for creation without this failing. | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import pytest | ||
|
|
||
| from adapter_processor_v2.adapter_processor import AdapterProcessor | ||
| from adapter_processor_v2.deprecated_adapters import ( | ||
| DEPRECATED_ADAPTERS, | ||
| get_deprecation_message, | ||
| is_adapter_deprecated, | ||
| ) | ||
| from adapter_processor_v2.exceptions import DeprecatedAdapter | ||
| from unstract.sdk1.adapters.adapterkit import Adapterkit | ||
|
|
||
| LLM_WHISPERER_V1 = "llmwhisperer|0a1647f0-f65f-410d-843b-3d979c78350e" | ||
|
|
||
| REQUIRED_METADATA_KEYS = {"reason", "deprecated_date", "adapter_name", "adapter_type"} | ||
|
|
||
|
|
||
| def test_llm_whisperer_v1_is_registered_as_deprecated(): | ||
| assert is_adapter_deprecated(LLM_WHISPERER_V1) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("adapter_id", sorted(DEPRECATED_ADAPTERS)) | ||
| def test_deprecated_adapter_is_not_in_sdk_registry(adapter_id): | ||
| """A deprecated adapter must not be registered in the SDK.""" | ||
| assert adapter_id not in Adapterkit().adapters | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("adapter_id", sorted(DEPRECATED_ADAPTERS)) | ||
| def test_deprecated_adapter_metadata_is_complete(adapter_id): | ||
| assert REQUIRED_METADATA_KEYS <= set(DEPRECATED_ADAPTERS[adapter_id]) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("adapter_id", sorted(DEPRECATED_ADAPTERS)) | ||
| def test_deprecated_adapter_is_not_offered_for_creation(adapter_id): | ||
| adapter_type = DEPRECATED_ADAPTERS[adapter_id]["adapter_type"] | ||
| offered = AdapterProcessor.get_all_supported_adapters( | ||
| user_email="someone@example.com", type=adapter_type | ||
| ) | ||
| assert adapter_id not in {adapter["id"] for adapter in offered} | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("adapter_id", sorted(DEPRECATED_ADAPTERS)) | ||
| def test_json_schema_is_refused_for_deprecated_adapter(adapter_id): | ||
| with pytest.raises(DeprecatedAdapter): | ||
| AdapterProcessor.get_json_schema(adapter_id) | ||
|
|
||
|
|
||
| def test_deprecation_message_names_the_replacement(): | ||
| message = get_deprecation_message(LLM_WHISPERER_V1) | ||
| assert "LLMWhisperer" in message | ||
| assert "V2" in message | ||
|
|
||
|
|
||
| def test_unknown_adapter_is_not_deprecated(): | ||
| assert not is_adapter_deprecated("openai|some-uuid") | ||
| assert not is_adapter_deprecated(None) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.