Skip to content

UN-2105 [FEAT] Include adapter name in error messages#1825

Open
pk-zipstack wants to merge 10 commits intomainfrom
feature/include-adapter-name-in-errors
Open

UN-2105 [FEAT] Include adapter name in error messages#1825
pk-zipstack wants to merge 10 commits intomainfrom
feature/include-adapter-name-in-errors

Conversation

@pk-zipstack
Copy link
Contributor

@pk-zipstack pk-zipstack commented Mar 5, 2026

What

  • Preserve the user-facing adapter instance name (e.g., "Unstract Trial LLM") from the platform service response and include it in SDK1 error messages across LLM, Embedding, VectorDB, and X2Text adapter consumers.

Why

  • When an adapter error occurs during workflow execution, the error message only showed the provider name (e.g., "azureopenai") or a raw instance UUID, making it difficult for users to identify which configured adapter caused the failure.
  • This was reported in UN-2105.

How

  • In PlatformHelper._get_adapter_configuration(), the adapter name was already fetched from the platform service but immediately discarded via pop(). Now it is stored back in the config dict under a private key _adapter_name.
  • Each adapter consumer (LLM, Embedding, VectorDB, X2Text) extracts this name during init and includes it in error messages.
    • Before: Error from LLM provider 'azureopenai': ...
    • After: Error from LLM adapter 'Unstract Trial LLM' (azureopenai): ...
  • Index key generation sites (index.py, utils/indexing.py, prompt-service index_v2.py) strip the _adapter_name key before hashing to maintain backward compatibility with existing document index keys.

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • No. The _adapter_name key is stripped before index key hashing, so existing indexed documents are unaffected. The only user-visible change is richer error messages that now include the adapter instance name alongside the provider name.

Database Migrations

  • None

Env Config

  • None

Relevant Docs

  • None

Related Issues or PRs

Dependencies Versions

  • None

Notes on Testing

  • Configure an adapter with a known name (e.g., "My OpenAI Adapter")
  • Trigger an adapter error (e.g., invalid credentials)
  • Verify the error message includes the adapter instance name

Screenshots

N/A

Checklist

I have read and understood the Contribution Guidelines.

Preserve the user-facing adapter name (e.g., "Unstract Trial LLM")
from the platform service response and include it in error messages
across SDK1 adapter consumers (LLM, Embedding, VectorDB, X2Text).

Previously, adapter names were discarded during config retrieval
and errors only showed provider names or instance IDs, making it
hard to identify which adapter caused the issue.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 5, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b56ad098-1471-4fe2-9607-20699a4e757e

📥 Commits

Reviewing files that changed from the base of the PR and between 7591cd4 and cb09ec3.

📒 Files selected for processing (4)
  • prompt-service/src/unstract/prompt_service/core/index_v2.py
  • unstract/sdk1/src/unstract/sdk1/index.py
  • unstract/sdk1/src/unstract/sdk1/utils/common.py
  • unstract/sdk1/src/unstract/sdk1/utils/indexing.py

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced error messages across embedding, vector database, and text extraction components to include adapter context, improving troubleshooting capabilities.
  • Improvements

    • Centralized and standardized adapter configuration handling for more consistent behavior across indexing and initialization processes.

Walkthrough

Introduce Common.ADAPTER_NAME and a Utils.strip_adapter_name helper; platform stores adapter-name metadata; adapter classes capture/stash adapter names for error context; indexing routines fetch and sanitize adapter configs to exclude adapter-name metadata from generated index keys.

Changes

Cohort / File(s) Summary
Constants
unstract/sdk1/src/unstract/sdk1/constants.py
Add Common.ADAPTER_NAME = "_adapter_name" to carry adapter-name metadata in adapter configs.
Common utils
unstract/sdk1/src/unstract/sdk1/utils/common.py
Add Utils.strip_adapter_name(*configs) to remove Common.ADAPTER_NAME from provided config dicts before hashing or serialization.
Platform config storage
unstract/sdk1/src/unstract/sdk1/platform.py
Store adapter name in the adapter configuration payload under Common.ADAPTER_NAME when building adapter_data.
Adapter classes — capture adapter name & error context
unstract/sdk1/src/unstract/sdk1/llm.py, unstract/sdk1/src/unstract/sdk1/embedding.py, unstract/sdk1/src/unstract/sdk1/vector_db.py, unstract/sdk1/src/unstract/sdk1/x2txt.py
Read and remove Common.ADAPTER_NAME from adapter configs (pop/default ""), store on instance (_adapter_name), and include adapter name (with fallback) in logs and raised error messages.
Indexing / key generation — sanitize adapter configs
unstract/sdk1/src/unstract/sdk1/index.py, unstract/sdk1/src/unstract/sdk1/utils/indexing.py, prompt-service/src/unstract/prompt_service/core/index_v2.py
Fetch vector_db/embedding/x2text configs via PlatformHelper, call Utils.strip_adapter_name(...), and use the sanitized configs when constructing index keys (prevent adapter-name from affecting hashes).
Public import adjustments
unstract/sdk1/src/unstract/sdk1/index.py, prompt-service/src/unstract/prompt_service/core/index_v2.py
Add Utils to imports where needed to access strip_adapter_name (no public API signature changes).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding adapter instance names to error messages across SDK1 adapters.
Description check ✅ Passed The description is comprehensive and follows the template structure with all required sections completed, including What, Why, How, breaking changes analysis, testing notes, and related issue reference.
Docstring Coverage ✅ Passed Docstring coverage is 85.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/include-adapter-name-in-errors
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
prompt-service/src/unstract/prompt_service/core/index_v2.py (1)

100-109: ⚠️ Potential issue | 🟠 Major

Pre-existing issue: file_hash may be undefined.

Note: This is not introduced by this PR, but file_hash is only assigned on line 81 when file_info.file_hash is falsy. When file_info.file_hash is truthy, the variable file_hash used on line 101 will be undefined, causing a NameError.

This should likely be:

file_hash = file_info.file_hash
if not file_hash:
    file_hash = fs.get_hash_from_file(path=file_info.file_path)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@prompt-service/src/unstract/prompt_service/core/index_v2.py` around lines 100
- 109, The variable file_hash can be undefined when file_info.file_hash is
truthy; update the assignment logic in the code that populates index_key so that
file_hash is always set from file_info.file_hash first (e.g., file_hash =
file_info.file_hash) and only call
fs.get_hash_from_file(path=file_info.file_path) when that value is falsy, then
use that ensured file_hash when building index_key (references: file_hash,
file_info, fs.get_hash_from_file, index_key, self.chunking_config.chunk_size/
chunk_overlap).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@unstract/sdk1/src/unstract/sdk1/embedding.py`:
- Around line 100-105: The async embedding error paths still call
parse_litellm_err with only provider values; update those calls to include the
adapter display string like the sync path does. Compute adapter_info using
self._adapter_name and self.adapter.get_name() (same logic as the shown
adapter_info variable) and pass adapter_info into parse_litellm_err instead of
the provider-only argument in all async error raises (search for
parse_litellm_err in this module, e.g., the async embedding functions around the
current raise and the other occurrences referenced). Ensure the raise statements
use "raise parse_litellm_err(e, adapter_info) from e" so adapter context is
included.

In `@unstract/sdk1/src/unstract/sdk1/llm.py`:
- Around line 266-273: The acomplete error path is building messages that only
include the provider name and drops the adapter instance name; update the error
construction in the acomplete handler to use the same adapter_info logic as
elsewhere (use self._adapter_name when present, formatted as
"'{self._adapter_name}' ({self.adapter.get_provider()})", else fall back to
"'{self.adapter.get_provider()}'") and use that adapter_info when composing
error_msg (same change should be applied to the other occurrence around lines
346-353) so async callers receive the adapter instance name in the error text.

---

Outside diff comments:
In `@prompt-service/src/unstract/prompt_service/core/index_v2.py`:
- Around line 100-109: The variable file_hash can be undefined when
file_info.file_hash is truthy; update the assignment logic in the code that
populates index_key so that file_hash is always set from file_info.file_hash
first (e.g., file_hash = file_info.file_hash) and only call
fs.get_hash_from_file(path=file_info.file_path) when that value is falsy, then
use that ensured file_hash when building index_key (references: file_hash,
file_info, fs.get_hash_from_file, index_key, self.chunking_config.chunk_size/
chunk_overlap).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ff0f61a0-7b62-4b96-ae66-eecf6097d69f

📥 Commits

Reviewing files that changed from the base of the PR and between e0c2af0 and 6b9dd9f.

📒 Files selected for processing (9)
  • prompt-service/src/unstract/prompt_service/core/index_v2.py
  • unstract/sdk1/src/unstract/sdk1/constants.py
  • unstract/sdk1/src/unstract/sdk1/embedding.py
  • unstract/sdk1/src/unstract/sdk1/index.py
  • unstract/sdk1/src/unstract/sdk1/llm.py
  • unstract/sdk1/src/unstract/sdk1/platform.py
  • unstract/sdk1/src/unstract/sdk1/utils/indexing.py
  • unstract/sdk1/src/unstract/sdk1/vector_db.py
  • unstract/sdk1/src/unstract/sdk1/x2txt.py

pk-zipstack and others added 3 commits March 12, 2026 09:36
Simplify adapter_info construction using or-chaining instead of
ternary conditionals to bring cognitive complexity back within the
SonarCloud limit of 15.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
unstract/sdk1/src/unstract/sdk1/embedding.py (1)

141-156: ⚠️ Potential issue | 🟠 Major

Async embedding errors still drop the adapter instance name.

Line 142 and Line 155 still pass provider-only values to parse_litellm_err(), so async callers miss the adapter-name context that the sync paths now include.

Proposed fix
         except Exception as e:
-            provider_name = f"{self.adapter.get_name()}"
-            raise parse_litellm_err(e, provider_name) from e
+            adapter_info = self._adapter_name or self.adapter.get_name()
+            raise parse_litellm_err(e, adapter_info) from e
@@
         except Exception as e:
-            provider_name = f"{self.adapter.get_name()}"
-            raise parse_litellm_err(e, provider_name) from e
+            adapter_info = self._adapter_name or self.adapter.get_name()
+            raise parse_litellm_err(e, adapter_info) from e
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@unstract/sdk1/src/unstract/sdk1/embedding.py` around lines 141 - 156, The
async method get_aembeddings constructs and passes only a provider string to
parse_litellm_err, losing the adapter-instance context; change its exception
handler to mirror the sync path by building the same adapter-aware identifier
used elsewhere (use the same expression the sync code uses to include the
adapter instance name) and pass that identifier into parse_litellm_err(e,
<adapter-aware-identifier>) instead of the current provider_name so async
callers receive the adapter name too.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@unstract/sdk1/src/unstract/sdk1/embedding.py`:
- Around line 141-156: The async method get_aembeddings constructs and passes
only a provider string to parse_litellm_err, losing the adapter-instance
context; change its exception handler to mirror the sync path by building the
same adapter-aware identifier used elsewhere (use the same expression the sync
code uses to include the adapter instance name) and pass that identifier into
parse_litellm_err(e, <adapter-aware-identifier>) instead of the current
provider_name so async callers receive the adapter name too.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6d1355c0-09a2-4691-9f8b-1307219df5a3

📥 Commits

Reviewing files that changed from the base of the PR and between 6b9dd9f and e1d4b1d.

📒 Files selected for processing (3)
  • unstract/sdk1/src/unstract/sdk1/embedding.py
  • unstract/sdk1/src/unstract/sdk1/index.py
  • unstract/sdk1/src/unstract/sdk1/llm.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • unstract/sdk1/src/unstract/sdk1/llm.py

pk-zipstack and others added 3 commits March 12, 2026 09:52
Apply same or-chaining simplification to LLM complete() and
stream_complete() error handlers to stay within SonarCloud's
cognitive complexity limit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
unstract/sdk1/src/unstract/sdk1/llm.py (1)

271-275: Consider extracting _adapter_info() helper and including provider context.

The error format shows either adapter name or provider, but the PR objectives suggest showing both: "Error from LLM adapter 'Unstract Trial LLM' (azureopenai): ...". This gives users the friendly name while retaining technical context for debugging.

Additionally, this logic is duplicated at lines 348 and 408. A helper method would improve consistency and maintainability.

♻️ Proposed refactor

Add a helper method to the class:

def _adapter_info(self) -> str:
    """Return formatted adapter identifier for error messages."""
    if self._adapter_name:
        return f"'{self._adapter_name}' ({self.adapter.get_provider()})"
    return f"'{self.adapter.get_provider()}'"

Then replace all three occurrences (lines 271-274, 348-351, 408-411):

-            adapter_info = self._adapter_name or self.adapter.get_provider()
-            error_msg = (
-                f"Error from LLM adapter '{adapter_info}': "
-                f"{strip_litellm_prefix(str(e))}"
-            )
+            error_msg = (
+                f"Error from LLM adapter {self._adapter_info()}: "
+                f"{strip_litellm_prefix(str(e))}"
+            )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@unstract/sdk1/src/unstract/sdk1/llm.py` around lines 271 - 275, Extract a new
instance helper method named _adapter_info(self) that returns a formatted
identifier combining the friendly adapter name and provider, e.g. when
self._adapter_name exists return f"'{self._adapter_name}'
({self.adapter.get_provider()})" else return f"'{self.adapter.get_provider()}'";
then replace the duplicated logic that builds adapter_info (the blocks using
self._adapter_name and self.adapter.get_provider()) with calls to
this._adapter_info() in the LLM class so all error messages use the same
formatted string.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@unstract/sdk1/src/unstract/sdk1/llm.py`:
- Around line 271-275: Extract a new instance helper method named
_adapter_info(self) that returns a formatted identifier combining the friendly
adapter name and provider, e.g. when self._adapter_name exists return
f"'{self._adapter_name}' ({self.adapter.get_provider()})" else return
f"'{self.adapter.get_provider()}'"; then replace the duplicated logic that
builds adapter_info (the blocks using self._adapter_name and
self.adapter.get_provider()) with calls to this._adapter_info() in the LLM class
so all error messages use the same formatted string.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c4f01a13-8eee-448d-92e6-286ea4f3abf8

📥 Commits

Reviewing files that changed from the base of the PR and between e1d4b1d and 7591cd4.

📒 Files selected for processing (1)
  • unstract/sdk1/src/unstract/sdk1/llm.py

Copy link
Contributor

@chandrasekharan-zipstack chandrasekharan-zipstack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for the most part, address the comment to reduce code duplication

pk-zipstack and others added 2 commits March 13, 2026 11:27
Move the repeated adapter-name stripping logic into
Utils.strip_adapter_name() in sdk1/utils/common.py, replacing
inline for-loops in index key generation across sdk1/index.py,
sdk1/utils/indexing.py, and prompt-service/core/index_v2.py.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Contributor

Test Results

Summary
  • Runner Tests: 11 passed, 0 failed (11 total)
  • SDK1 Tests: 63 passed, 0 failed (63 total)

Runner Tests - Full Report
filepath function $$\textcolor{#23d18b}{\tt{passed}}$$ SUBTOTAL
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_logs}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_cleanup}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_cleanup\_skip}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_client\_init}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image\_exists}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_container\_run\_config}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_container\_run\_config\_without\_mount}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_run\_container}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image\_for\_sidecar}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_sidecar\_container}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{TOTAL}}$$ $$\textcolor{#23d18b}{\tt{11}}$$ $$\textcolor{#23d18b}{\tt{11}}$$
SDK1 Tests - Full Report
filepath function $$\textcolor{#23d18b}{\tt{passed}}$$ SUBTOTAL
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_success\_on\_first\_attempt}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_retry\_on\_connection\_error}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_non\_retryable\_http\_error}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_retryable\_http\_errors}}$$ $$\textcolor{#23d18b}{\tt{3}}$$ $$\textcolor{#23d18b}{\tt{3}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_post\_method\_retry}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_retry\_logging}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_prompt.py}}$$ $$\textcolor{#23d18b}{\tt{TestPromptToolRetry.test\_success\_on\_first\_attempt}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_prompt.py}}$$ $$\textcolor{#23d18b}{\tt{TestPromptToolRetry.test\_retry\_on\_errors}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_prompt.py}}$$ $$\textcolor{#23d18b}{\tt{TestPromptToolRetry.test\_wrapper\_methods\_retry}}$$ $$\textcolor{#23d18b}{\tt{4}}$$ $$\textcolor{#23d18b}{\tt{4}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_connection\_error\_is\_retryable}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_timeout\_is\_retryable}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_http\_error\_retryable\_status\_codes}}$$ $$\textcolor{#23d18b}{\tt{3}}$$ $$\textcolor{#23d18b}{\tt{3}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_http\_error\_non\_retryable\_status\_codes}}$$ $$\textcolor{#23d18b}{\tt{5}}$$ $$\textcolor{#23d18b}{\tt{5}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_http\_error\_without\_response}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_os\_error\_retryable\_errno}}$$ $$\textcolor{#23d18b}{\tt{5}}$$ $$\textcolor{#23d18b}{\tt{5}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_os\_error\_non\_retryable\_errno}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_other\_exception\_not\_retryable}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_exponential\_backoff\_without\_jitter}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_exponential\_backoff\_with\_jitter}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_max\_delay\_cap}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_max\_delay\_cap\_with\_jitter}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_successful\_call\_first\_attempt}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_retry\_after\_transient\_failure}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_max\_retries\_exceeded}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_retry\_with\_custom\_predicate}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_no\_retry\_with\_predicate\_false}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_exception\_not\_in\_tuple\_not\_retried}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_default\_configuration}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_environment\_variable\_configuration}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_invalid\_max\_retries}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_invalid\_base\_delay}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_invalid\_multiplier}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_jitter\_values}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_custom\_exceptions\_only}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_custom\_predicate\_only}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_both\_exceptions\_and\_predicate}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_exceptions\_match\_but\_predicate\_false}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_retry\_platform\_service\_call\_exists}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_retry\_prompt\_service\_call\_exists}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_platform\_service\_decorator\_retries\_on\_connection\_error}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_prompt\_service\_decorator\_retries\_on\_timeout}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryLogging.test\_warning\_logged\_on\_retry}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryLogging.test\_info\_logged\_on\_success\_after\_retry}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryLogging.test\_exception\_logged\_on\_giving\_up}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{TOTAL}}$$ $$\textcolor{#23d18b}{\tt{63}}$$ $$\textcolor{#23d18b}{\tt{63}}$$

@sonarqubecloud
Copy link

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 13, 2026

Greptile Summary

This PR improves the user-facing error messages for all four SDK1 adapter types (LLM, Embedding, VectorDB, X2Text) by preserving the human-readable adapter instance name (e.g. "Unstract Trial LLM") from the platform service response and embedding it in error messages, replacing raw UUIDs or cryptic provider identifiers.

Key changes:

  • PlatformHelper._get_adapter_configuration() now stores the previously-discarded adapter_name back into the config dict under the private key _adapter_name (Common.ADAPTER_NAME).
  • Each adapter consumer (LLM, Embedding, VectorDB, X2Text) pops this key during initialisation and stores it as self._adapter_name for use in error paths.
  • A new Utils.strip_adapter_name(*configs) utility removes the _adapter_name key before adapter configs are hashed for index key generation across index.py, utils/indexing.py, and prompt-service/core/index_v2.py, preserving full backward compatibility with existing indexed documents.
  • Bug: Embedding.get_aembedding() and Embedding.get_aembeddings() were not updated — both async methods still use self.adapter.get_name() directly, missing the _adapter_name enhancement that was applied to the sync counterparts.
  • Style: The PR description specifies the format Error from LLM adapter 'Unstract Trial LLM' (azureopenai): ... (adapter name plus provider in parentheses), but the implementation uses _adapter_name or provider — omitting the provider when a name is present. VectorDB and X2Text also show minor inconsistency in how the identifier is quoted in error messages.

Confidence Score: 4/5

  • Safe to merge with one logic bug fix needed in the async embedding methods before release.
  • The core approach is sound — the private _adapter_name key is well-scoped, properly stripped before hashing, and does not affect existing index keys. The main issue is that Embedding.get_aembedding() and Embedding.get_aembeddings() were missed during the update, so async embedding error paths will still show the old provider name. This is a functional gap but limited to async embedding error reporting only. The secondary issue (missing provider context in the format string vs. the PR description) is a minor UX concern that doesn't break anything.
  • unstract/sdk1/src/unstract/sdk1/embedding.py — async methods need the same _adapter_name treatment applied to the sync methods.

Important Files Changed

Filename Overview
unstract/sdk1/src/unstract/sdk1/platform.py Stores adapter name under the private _adapter_name key in the config dict returned by _get_adapter_configuration(), replacing the previous pop() that discarded it. Safe change; the key is stripped downstream before hashing.
unstract/sdk1/src/unstract/sdk1/llm.py Pops _adapter_name from the config and uses it in all three error paths (complete, stream_complete, acomplete). Error messages now show the adapter name but drop the provider name, diverging from the PR description's stated format of 'Name (provider)'.
unstract/sdk1/src/unstract/sdk1/embedding.py Sync methods (get_embedding, get_embeddings) correctly adopt _adapter_name, but the async counterparts get_aembedding() (line 142) and get_aembeddings() (line 155) were not updated and still use self.adapter.get_name() directly — a clear omission.
unstract/sdk1/src/unstract/sdk1/vector_db.py Pops _adapter_name before building the adapter instance; uses it in error logging and the raised VectorDBError. Minor inconsistency: the adapter name/UUID identifier is quoted inside adapter_info conditionally rather than always in the template string.
unstract/sdk1/src/unstract/sdk1/x2txt.py Same pattern as VectorDB: pops _adapter_name and uses it in the initialisation error handler. The index.py usage of getattr(x2text, "_adapter_name", "") is safe because _adapter_name is always set before process() can be called.
unstract/sdk1/src/unstract/sdk1/utils/common.py Adds Utils.strip_adapter_name(*configs) — a clean, well-documented utility that removes _adapter_name from adapter configs before index key hashing to preserve backward compatibility.
unstract/sdk1/src/unstract/sdk1/utils/indexing.py Fetches configs, strips _adapter_name via Utils.strip_adapter_name(), then builds the index key dict. Correctly preserves backward compatibility with existing document index hashes.
unstract/sdk1/src/unstract/sdk1/index.py Both the X2Text error handler and _generate_index_key() are updated correctly: adapter name is used in the error message, and configs are stripped of _adapter_name before hashing.
prompt-service/src/unstract/prompt_service/core/index_v2.py Mirrors the index.py pattern: fetches configs independently, strips _adapter_name, then builds the index key. Correctly imports and uses Utils.

Sequence Diagram

sequenceDiagram
    participant Tool
    participant Platform as PlatformHelper
    participant Consumer as Adapter Consumer
    participant IdxGen as Index Key Generator

    Tool->>Platform: get_adapter_config(instance_id)
    Platform-->>Platform: pop adapter_name & adapter_type from response
    Platform-->>Platform: store under _adapter_name key
    Platform-->>Consumer: return config dict (includes _adapter_name)

    Consumer->>Consumer: pop _adapter_name → self._adapter_name
    Consumer->>Consumer: initialise adapter (clean config)

    alt Error during adapter call
        Consumer-->>Tool: raise Error with adapter name in message
    end

    Tool->>IdxGen: generate_index_key(...)
    IdxGen->>Platform: get_adapter_config (x3 for vdb, emb, x2text)
    Platform-->>IdxGen: configs (each includes _adapter_name)
    IdxGen->>IdxGen: Utils.strip_adapter_name(configs)
    IdxGen->>IdxGen: json.dumps + hash
    IdxGen-->>Tool: hashed index key (backward compatible)
Loading

Comments Outside Diff (1)

  1. unstract/sdk1/src/unstract/sdk1/embedding.py, line 142-143 (link)

    Async embedding methods miss _adapter_name enhancement

    get_aembedding() and get_aembeddings() (lines 142–156) were not updated alongside their synchronous counterparts. Both still use provider_name = f"{self.adapter.get_name()}" directly, so errors from async embedding calls will still show the raw provider name instead of the user-facing adapter instance name.

    The same fix applies to get_aembeddings() at line 155–156.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: unstract/sdk1/src/unstract/sdk1/embedding.py
    Line: 142-143
    
    Comment:
    **Async embedding methods miss `_adapter_name` enhancement**
    
    `get_aembedding()` and `get_aembeddings()` (lines 142–156) were not updated alongside their synchronous counterparts. Both still use `provider_name = f"{self.adapter.get_name()}"` directly, so errors from async embedding calls will still show the raw provider name instead of the user-facing adapter instance name.
    
    
    
    The same fix applies to `get_aembeddings()` at line 155–156.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: unstract/sdk1/src/unstract/sdk1/embedding.py
Line: 142-143

Comment:
**Async embedding methods miss `_adapter_name` enhancement**

`get_aembedding()` and `get_aembeddings()` (lines 142–156) were not updated alongside their synchronous counterparts. Both still use `provider_name = f"{self.adapter.get_name()}"` directly, so errors from async embedding calls will still show the raw provider name instead of the user-facing adapter instance name.

```suggestion
            adapter_info = self._adapter_name or self.adapter.get_name()
            raise parse_litellm_err(e, adapter_info) from e
```

The same fix applies to `get_aembeddings()` at line 155–156.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: unstract/sdk1/src/unstract/sdk1/llm.py
Line: 271-274

Comment:
**Error message loses provider context when adapter name is present**

The PR description states the intended "after" format as `Error from LLM adapter 'Unstract Trial LLM' (azureopenai): ...`, preserving the provider name alongside the human-readable adapter name for easier debugging. However, the current implementation uses `adapter_info = self._adapter_name or self.adapter.get_provider()`, which means when `_adapter_name` is set the provider name is completely absent from the error message.

Consider including both to match the stated goal:
```suggestion
            adapter_name = self._adapter_name
            provider = self.adapter.get_provider()
            adapter_info = f"{adapter_name} ({provider})" if adapter_name else provider
            error_msg = (
                f"Error from LLM adapter '{adapter_info}': "
                f"{strip_litellm_prefix(str(e))}"
            )
```

The same pattern applies to `stream_complete()` (line ~349) and `acomplete()` (line ~408).

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: unstract/sdk1/src/unstract/sdk1/vector_db.py
Line: 112-123

Comment:
**Inconsistent quote handling in error message identifier**

`VectorDB` (and `X2Text` at `x2txt.py` lines 89–97) embed the quotes inside `adapter_info` (`f"'{adapter_name}'"`) only when a name exists, leaving the raw UUID unquoted as a fallback. By contrast, the LLM and Embedding adapters always place the identifier inside quotes via the template string (`f"Error from LLM adapter '{adapter_info}': ..."`). This results in different message styles:

- With a name: `Unable to get vector_db 'My VectorDB': ...`  ← quoted
- Without a name: `Unable to get vector_db some-uuid-here: ...`  ← unquoted

For consistency, move the quotes into the template string and let `adapter_info` stay as the plain string (either the name or the UUID):

```suggestion
            adapter_name = getattr(self, "_adapter_name", "")
            adapter_info = adapter_name if adapter_name else self._adapter_instance_id
            self._tool.stream_log(
                log=f"Unable to get vector_db '{adapter_info}': {e}",
                level=LogLevel.ERROR,
            )
            raise VectorDBError(
                f"Error getting vectorDB instance '{adapter_info}': {e}"
            ) from e
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: cb09ec3

Comment on lines +271 to 274
adapter_info = self._adapter_name or self.adapter.get_provider()
error_msg = (
f"Error from LLM provider '{self.adapter.get_provider()}': "
f"Error from LLM adapter '{adapter_info}': "
f"{strip_litellm_prefix(str(e))}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error message loses provider context when adapter name is present

The PR description states the intended "after" format as Error from LLM adapter 'Unstract Trial LLM' (azureopenai): ..., preserving the provider name alongside the human-readable adapter name for easier debugging. However, the current implementation uses adapter_info = self._adapter_name or self.adapter.get_provider(), which means when _adapter_name is set the provider name is completely absent from the error message.

Consider including both to match the stated goal:

Suggested change
adapter_info = self._adapter_name or self.adapter.get_provider()
error_msg = (
f"Error from LLM provider '{self.adapter.get_provider()}': "
f"Error from LLM adapter '{adapter_info}': "
f"{strip_litellm_prefix(str(e))}"
adapter_name = self._adapter_name
provider = self.adapter.get_provider()
adapter_info = f"{adapter_name} ({provider})" if adapter_name else provider
error_msg = (
f"Error from LLM adapter '{adapter_info}': "
f"{strip_litellm_prefix(str(e))}"
)

The same pattern applies to stream_complete() (line ~349) and acomplete() (line ~408).

Prompt To Fix With AI
This is a comment left during a code review.
Path: unstract/sdk1/src/unstract/sdk1/llm.py
Line: 271-274

Comment:
**Error message loses provider context when adapter name is present**

The PR description states the intended "after" format as `Error from LLM adapter 'Unstract Trial LLM' (azureopenai): ...`, preserving the provider name alongside the human-readable adapter name for easier debugging. However, the current implementation uses `adapter_info = self._adapter_name or self.adapter.get_provider()`, which means when `_adapter_name` is set the provider name is completely absent from the error message.

Consider including both to match the stated goal:
```suggestion
            adapter_name = self._adapter_name
            provider = self.adapter.get_provider()
            adapter_info = f"{adapter_name} ({provider})" if adapter_name else provider
            error_msg = (
                f"Error from LLM adapter '{adapter_info}': "
                f"{strip_litellm_prefix(str(e))}"
            )
```

The same pattern applies to `stream_complete()` (line ~349) and `acomplete()` (line ~408).

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 112 to +123
except Exception as e:
adapter_name = getattr(self, "_adapter_name", "")
adapter_info = (
f"'{adapter_name}'" if adapter_name else self._adapter_instance_id
)
self._tool.stream_log(
log=f"Unable to get vector_db {self._adapter_instance_id}: {e}",
log=f"Unable to get vector_db {adapter_info}: {e}",
level=LogLevel.ERROR,
)
raise VectorDBError(f"Error getting vectorDB instance: {e}") from e
raise VectorDBError(
f"Error getting vectorDB instance {adapter_info}: {e}"
) from e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent quote handling in error message identifier

VectorDB (and X2Text at x2txt.py lines 89–97) embed the quotes inside adapter_info (f"'{adapter_name}'") only when a name exists, leaving the raw UUID unquoted as a fallback. By contrast, the LLM and Embedding adapters always place the identifier inside quotes via the template string (f"Error from LLM adapter '{adapter_info}': ..."). This results in different message styles:

  • With a name: Unable to get vector_db 'My VectorDB': ... ← quoted
  • Without a name: Unable to get vector_db some-uuid-here: ... ← unquoted

For consistency, move the quotes into the template string and let adapter_info stay as the plain string (either the name or the UUID):

Suggested change
except Exception as e:
adapter_name = getattr(self, "_adapter_name", "")
adapter_info = (
f"'{adapter_name}'" if adapter_name else self._adapter_instance_id
)
self._tool.stream_log(
log=f"Unable to get vector_db {self._adapter_instance_id}: {e}",
log=f"Unable to get vector_db {adapter_info}: {e}",
level=LogLevel.ERROR,
)
raise VectorDBError(f"Error getting vectorDB instance: {e}") from e
raise VectorDBError(
f"Error getting vectorDB instance {adapter_info}: {e}"
) from e
adapter_name = getattr(self, "_adapter_name", "")
adapter_info = adapter_name if adapter_name else self._adapter_instance_id
self._tool.stream_log(
log=f"Unable to get vector_db '{adapter_info}': {e}",
level=LogLevel.ERROR,
)
raise VectorDBError(
f"Error getting vectorDB instance '{adapter_info}': {e}"
) from e
Prompt To Fix With AI
This is a comment left during a code review.
Path: unstract/sdk1/src/unstract/sdk1/vector_db.py
Line: 112-123

Comment:
**Inconsistent quote handling in error message identifier**

`VectorDB` (and `X2Text` at `x2txt.py` lines 89–97) embed the quotes inside `adapter_info` (`f"'{adapter_name}'"`) only when a name exists, leaving the raw UUID unquoted as a fallback. By contrast, the LLM and Embedding adapters always place the identifier inside quotes via the template string (`f"Error from LLM adapter '{adapter_info}': ..."`). This results in different message styles:

- With a name: `Unable to get vector_db 'My VectorDB': ...`  ← quoted
- Without a name: `Unable to get vector_db some-uuid-here: ...`  ← unquoted

For consistency, move the quotes into the template string and let `adapter_info` stay as the plain string (either the name or the UUID):

```suggestion
            adapter_name = getattr(self, "_adapter_name", "")
            adapter_info = adapter_name if adapter_name else self._adapter_instance_id
            self._tool.stream_log(
                log=f"Unable to get vector_db '{adapter_info}': {e}",
                level=LogLevel.ERROR,
            )
            raise VectorDBError(
                f"Error getting vectorDB instance '{adapter_info}': {e}"
            ) from e
```

How can I resolve this? If you propose a fix, please make it concise.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants