-
Notifications
You must be signed in to change notification settings - Fork 709
UN-3142 [FEAT] Trace an execution to its LLMWhisperer call #2246
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
1
commit into
main
Choose a base branch
from
UN-3142-whisper-hash-tracing
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.
Open
Changes from all commits
Commits
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
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
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
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,148 @@ | ||
| """Tests for the source filename sent to LLMWhisperer (UN-3142). | ||
|
|
||
| Execution streams the document from its internal copy (``INFILE``), so the path | ||
| that reaches the adapter carries no usable name and LLMWhisperer's reports had | ||
| nothing to identify the call by. The real name travels in ``usage_kwargs``, | ||
| which every caller already populates, and is forwarded as the client's | ||
| ``filename`` param. | ||
|
|
||
| Pins: | ||
| - ``X2Text.process`` injects the name from ``usage_kwargs`` | ||
| - an explicit ``file_name`` kwarg wins over ``usage_kwargs`` | ||
| - the adapter forwards it into ``WhispererRequestParams`` | ||
| - ``get_whisperer_params`` emits it as ``filename``, defaulting to empty | ||
| - injecting it does not disturb the existing ``tag`` behaviour | ||
| """ | ||
|
|
||
| from typing import Any | ||
| from unittest.mock import MagicMock, patch | ||
|
|
||
| import pytest | ||
| from unstract.sdk1.adapters.x2text.constants import X2TextConstants | ||
| from unstract.sdk1.adapters.x2text.dto import ( | ||
| TextExtractionMetadata, | ||
| TextExtractionResult, | ||
| ) | ||
| from unstract.sdk1.adapters.x2text.llm_whisperer_v2.src.constants import ( | ||
| WhispererConfig, | ||
| ) | ||
| from unstract.sdk1.adapters.x2text.llm_whisperer_v2.src.dto import ( | ||
| WhispererRequestParams, | ||
| ) | ||
| from unstract.sdk1.adapters.x2text.llm_whisperer_v2.src.helper import ( | ||
| LLMWhispererHelper, | ||
| ) | ||
| from unstract.sdk1.adapters.x2text.llm_whisperer_v2.src.llm_whisperer_v2 import ( | ||
| LLMWhispererV2, | ||
| ) | ||
| from unstract.sdk1.constants import UsageKwargs | ||
| from unstract.sdk1.file_storage import FileStorage | ||
| from unstract.sdk1.x2txt import X2Text | ||
|
|
||
|
|
||
| def _make_x2text(usage_kwargs: dict[str, Any]) -> X2Text: | ||
| """Build an X2Text with adapter initialisation bypassed.""" | ||
| x2text = X2Text.__new__(X2Text) | ||
| x2text._tool = MagicMock() | ||
| x2text._usage_kwargs = usage_kwargs | ||
| x2text._x2text_instance = MagicMock() | ||
| x2text._x2text_instance.process.return_value = TextExtractionResult( | ||
| extracted_text="text", | ||
| extraction_metadata=TextExtractionMetadata(whisper_hash="h-1"), | ||
| ) | ||
| return x2text | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def mock_fs() -> MagicMock: | ||
| fs = MagicMock() | ||
| fs.mime_type.return_value = "application/pdf" | ||
| return fs | ||
|
|
||
|
|
||
| class TestX2TextInjectsSourceFilename: | ||
| @patch.object(X2Text, "push_usage_details", MagicMock()) | ||
| def test_filename_taken_from_usage_kwargs(self, mock_fs: MagicMock) -> None: | ||
| x2text = _make_x2text({UsageKwargs.FILE_NAME: "invoice-2024.pdf"}) | ||
|
|
||
| x2text.process(input_file_path="/data/exec/abc/INFILE", fs=mock_fs) | ||
|
|
||
| kwargs = x2text._x2text_instance.process.call_args.kwargs | ||
| assert kwargs[X2TextConstants.FILE_NAME] == "invoice-2024.pdf" | ||
|
|
||
| @patch.object(X2Text, "push_usage_details", MagicMock()) | ||
| def test_explicit_kwarg_wins_over_usage_kwargs(self, mock_fs: MagicMock) -> None: | ||
| """The agentic path passes the name directly rather than via usage.""" | ||
| x2text = _make_x2text({UsageKwargs.FILE_NAME: "from-usage.pdf"}) | ||
|
|
||
| x2text.process( | ||
| input_file_path="/data/exec/abc/INFILE", | ||
| fs=mock_fs, | ||
| file_name="explicit.pdf", | ||
| ) | ||
|
|
||
| kwargs = x2text._x2text_instance.process.call_args.kwargs | ||
| assert kwargs[X2TextConstants.FILE_NAME] == "explicit.pdf" | ||
|
|
||
| @patch.object(X2Text, "push_usage_details", MagicMock()) | ||
| def test_absent_usage_kwargs_yields_none(self, mock_fs: MagicMock) -> None: | ||
| """No name available must not raise — LLMWhisperer just gets the default.""" | ||
| x2text = _make_x2text({}) | ||
|
|
||
| x2text.process(input_file_path="/data/exec/abc/INFILE", fs=mock_fs) | ||
|
|
||
| kwargs = x2text._x2text_instance.process.call_args.kwargs | ||
| assert kwargs[X2TextConstants.FILE_NAME] is None | ||
|
|
||
|
|
||
| class TestAdapterForwardsFilename: | ||
| def test_process_forwards_filename_to_request_params(self) -> None: | ||
| adapter = LLMWhispererV2(settings={}) | ||
| captured: dict[str, WhispererRequestParams] = {} | ||
|
|
||
| def _capture( | ||
| input_file_path: str, | ||
| config: dict[str, Any], | ||
| extra_params: WhispererRequestParams, | ||
| fs: FileStorage | None = None, | ||
| ) -> dict[str, Any]: | ||
| captured["params"] = extra_params | ||
| return {"result_text": "text", "whisper_hash": "h-1"} | ||
|
|
||
| with patch.object( | ||
| LLMWhispererHelper, "send_whisper_request", side_effect=_capture | ||
| ): | ||
| adapter.process( | ||
| input_file_path="/data/exec/abc/INFILE", | ||
| fs=MagicMock(), | ||
| **{X2TextConstants.FILE_NAME: "statement.pdf"}, | ||
| ) | ||
|
|
||
| assert captured["params"].filename == "statement.pdf" | ||
|
|
||
|
|
||
| class TestWhispererParams: | ||
| def test_filename_included_in_query_params(self) -> None: | ||
| params = LLMWhispererHelper.get_whisperer_params( | ||
| config={}, | ||
| extra_params=WhispererRequestParams(filename="contract.pdf"), | ||
| ) | ||
|
|
||
| assert params[WhispererConfig.FILENAME] == "contract.pdf" | ||
|
|
||
| def test_filename_defaults_to_empty_when_unknown(self) -> None: | ||
| params = LLMWhispererHelper.get_whisperer_params( | ||
| config={}, extra_params=WhispererRequestParams() | ||
| ) | ||
|
|
||
| assert params[WhispererConfig.FILENAME] == "" | ||
|
|
||
| def test_tag_behaviour_unchanged(self) -> None: | ||
| """Filename must not disturb the tag, which carries customer tags.""" | ||
| params = LLMWhispererHelper.get_whisperer_params( | ||
| config={}, | ||
| extra_params=WhispererRequestParams(tag=["customer-tag"], filename="doc.pdf"), | ||
| ) | ||
|
|
||
| assert params[WhispererConfig.TAG] == "customer-tag" | ||
| assert params[WhispererConfig.FILENAME] == "doc.pdf" |
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When an agentic studio tool extracts a document through
_run_agentic_extraction, this directX2Textcall consumes onlyextracted_textand discardsextraction_metadata.whisper_hash, causing the hash to be absent fromMETADATA.jsonand customer-facing execution logs.Knowledge Base Used: Workers (Celery) Service
Prompt To Fix With AI