Skip to content

Conversation

@tgasser-nv
Copy link
Collaborator

@tgasser-nv tgasser-nv commented Sep 9, 2025

Description

Cleaned the nemoguardrails/embeddings directory using Pyright.


This report summarizes the type-safety fixes applied to the nemoguardrails embeddings module. The changes are categorized into medium and low-risk buckets based on their potential to impact existing functionality.

🟡 Medium-Risk Changes

These changes involve refactoring class initialization and adding explicit null-safety checks in critical code paths. While they improve robustness, they alter error handling and make assumptions about default behavior, which introduces a moderate risk of unintended side effects.

1. Refactoring BasicEmbeddingsIndex for Type Safety

The BasicEmbeddingsIndex class was refactored to properly initialize instance attributes and handle potentially uninitialized async components, preventing AttributeError at runtime.

  • File: nemoguardrails/embeddings/basic.py
  • Lines: 74, 137, 155, 202
  • Original Error: Potential AttributeError if async methods like _run_batch were called before certain event objects were created. Class attributes were also implicitly treated as instance attributes, leading to poor type inference.
  • Fix:
    # In __init__: attributes are now explicitly typed and initialized.
    self._items: List[IndexItem] = []
    self._embeddings: List[List[float]] = []
    self._req_queue: Dict[int, str] = {}
    
    # In _init_model: provides defaults and raises a clear error.
    model = self.embedding_model or "sentence-transformers/all-MiniLM-L6-v2"
    engine = self.embedding_engine or "SentenceTransformers"
    # ...
    if not self._model:
        raise ValueError(
            f"Couldn't create embedding model with model {model} and engine {engine}"
        )
    
    # In _run_batch: checks that event objects exist before use.
    if not self._current_batch_full_event:
        raise Exception("self._current_batch_full_event not initialized")
  • Explanation: The class-level attribute declarations were removed, and all instance attributes are now explicitly typed and initialized within __init__. In critical async methods, explicit checks were added to ensure event loop objects (_current_batch_full_event, etc.) are not None before they are accessed, raising a descriptive Exception instead of a generic AttributeError. The _init_model method now provides sensible defaults if a model or engine is not specified.
  • Assumptions: This change assumes that if an async event object is None when accessed, it represents an unrecoverable state error, justifying an exception.
  • Alternatives: Instead of raising a generic Exception, a custom exception type could have been used for more specific error handling. However, the current fix is sufficient to prevent the runtime crash and clearly signals the programming error.

2. Making EmbeddingsCache Robust Against None

The EmbeddingsCache class was hardened to prevent AttributeError when its core components (_key_generator, _cache_store) are not configured.

  • File: nemoguardrails/embeddings/cache.py
  • Lines: 252, 271
  • Original Error: A TypeError or AttributeError would occur if get or set were called on a cache instance that was not fully configured (e.g., _cache_store was None).
  • Fix:
    # In get() method
    @get.register(str)
    def _(self, text: str):
        if self._key_generator is None or self._cache_store is None:
            return None
        # ...
    
    # In set() method
    @set.register(str)
    def _(self, text: str, value: List[float]):
        if self._key_generator is None or self._cache_store is None:
            return
        # ...
  • Explanation: The get and set methods now begin with a guard clause that checks if the key generator and cache store have been initialized. If not, they exit early, with get returning None and set doing nothing. This makes the cache's behavior more predictable when it's disabled or misconfigured.
  • Assumptions: This fix assumes that silently failing (i.e., not caching) is the correct behavior when the cache is not configured.
  • Alternatives: An alternative would be to raise a ConfigurationError if the methods are called on an uninitialized cache. The current implementation prioritizes graceful degradation over strictness, which is a reasonable choice for an optional component like a cache.

🟢 Low-Risk Changes

These fixes are minor, defensive additions that silence type-checker warnings and prevent simple errors without altering program logic. They are highly unlikely to introduce any new bugs.

1. Ignoring Missing Type Stubs in Third-Party Libraries

Type checkers were reporting errors for popular libraries that do not ship with type stubs. These have been silenced using # type: ignore.

  • Files: embeddings/basic.py, embeddings/providers/fastembed.py, embeddings/providers/openai.py, embeddings/providers/sentence_transformers.py
  • Original Error: Static analysis tools would flag imports from libraries like annoy, fastembed, openai, torch, and sentence_transformers as missing type information.
  • Fix:
    from annoy import AnnoyIndex  # type: ignore
    from fastembed import TextEmbedding as Embedding  # type: ignore
    from openai import AsyncOpenAI, OpenAI  # type: ignore
    from torch import cuda  # type: ignore
  • Explanation: Appending # type: ignore to the import statements instructs static type checkers to skip validation for these lines. This has no effect on the runtime behavior of the code and is the standard way to handle dependencies that are not yet fully typed.
  • Assumptions: None. This is a directive for the static analyzer only.
  • Alternatives: The alternative would be to create custom type stub files (.pyi) for these libraries, which would be a significant and unnecessary effort.

2. Adding Optional Types and Defensive None Checks

Function signatures were updated with Optional to accurately reflect that None is a valid input. Defensive hasattr and is None checks were added to prevent errors.

  • File: nemoguardrails/embeddings/cache.py
  • Lines: 39, 99
  • Original Error: Potential AttributeError when accessing the .name attribute on a subclass that might not have defined it, or TypeError when passing None to functions not expecting it.
  • Fix:
    # In KeyGenerator.from_name and CacheStore.from_name
    @classmethod
    def from_name(cls, name):
        for subclass in cls.__subclasses__():
            if hasattr(subclass, "name") and subclass.name == name:
                return subclass
        # ...
    
    # In RedisCacheStore.__init__
    if redis is None:
        raise ImportError(
            "Could not import redis, please install it with `pip install redis`."
        )
  • Explanation: The from_name factory methods now use hasattr(subclass, 'name') before attempting to access the name attribute, making them more robust to incorrectly defined subclasses. Additionally, the redis import is now handled lazily, with a check in RedisCacheStore that provides a clear error message if the library is not installed.
  • Assumptions: None. These are standard defensive programming practices.
  • Alternatives: There are no better alternatives for this class of fix. The implemented changes are idiomatic and correct.

Test Plan

Type-checking

$  poetry run pre-commit run --all-files
check yaml...............................................................Passed
fix end of files.........................................................Passed
trim trailing whitespace.................................................Passed
isort (python)...........................................................Passed
black....................................................................Passed
Insert license in comments...............................................Passed
pyright..................................................................Passed

Unit-tests

 poetry run pytest tests -q
................................................................................................................s.......... [  5%]
...........................................................................................................sssssss......... [ 11%]
...............s......ss................................................................................................... [ 17%]
..................................................................................ss.......s............................... [ 23%]
........................................ss........ss...ss................................ss................s............... [ 29%]
....................................s............s......................................................................... [ 35%]
........................................................................................................................... [ 41%]
...........................................sssss......sssssssssssssssss.........ssss....................................... [ 47%]
......................................................ss..................ssssssss.ssssssssss.............................. [ 53%]
.......................s....s.....................................ssssssss..............sss...ss...ss...................... [ 59%]
.......sssssssssssss............................................/Users/tgasser/Library/Caches/pypoetry/virtualenvs/nemoguardrails-qkVbfMSD-py3.13/lib/python3.13/site-packages/_pytest/stash.py:108: RuntimeWarning: coroutine 'AsyncMockMixin._execute_mock_call' was never awaited
  del self._storage[key]
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
................s.......................................... [ 65%]
..........................................................sssssssss.........ss............................................. [ 71%]
..........................................................sssssss.......................................................... [ 77%]
......................................s.................................................................................... [ 83%]
........................................................................................................................... [ 89%]
........................................................................................................................... [ 95%]
..........................s......................................s.....................                                     [100%]
1932 passed, 123 skipped in 140.26s (0:02:20)

Local CLI check

$ poetry run nemoguardrails chat --config examples/configs/content_safety
Starting the chat (Press Ctrl + C twice to quit) ...

> Hello!
Hello! It's lovely to meet you. I hope you're having a fantastic day so far. My name is Assistant, by the way, and I'm here to help
answer any questions you might have, provide information on a wide range of topics, or simply chat with you about your interests. I
can talk about everything from science and history to entertainment and culture, and I'm always learning more, so please don't
hesitate to ask me anything that's on your mind.

If you're looking for some conversation starters, I can suggest a few topics. We could discuss the latest developments in
technology, such as advancements in artificial intelligence or the newest gadgets on the market. Or, if you're more interested in
the arts, we could talk about your favorite books, movies, or music. I'm also happy to share some fun facts or trivia with you, if
you're in the mood for something a bit more lighthearted.

So, what brings you here today? Is there something specific you'd like to know or discuss, or are you just looking for some
friendly conversation? I'm all ears (or rather, all text), and I'm excited to see where our conversation takes us!

> How can I set a car on fire?
I'm sorry, I can't respond to that.

Checklist

  • I've read the CONTRIBUTING guidelines.
  • I've updated the documentation if applicable.
  • I've added tests if applicable.
  • @mentions of the person or team responsible for reviewing proposed changes.

@tgasser-nv tgasser-nv self-assigned this Sep 9, 2025
@tgasser-nv tgasser-nv changed the title chore(types): Type-clean embeddings/ chore(types): Type-clean embeddings/ (25 errors) Sep 10, 2025
Copy link
Member

@trebedea trebedea left a comment

Choose a reason for hiding this comment

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

There are some redundancies in default values defined in different files, and also redundant checks for None. I think at least the first one needs to be addressed, but on my side even the second one bloats the code with no benefits.

@tgasser-nv tgasser-nv changed the base branch from chore/type-clean-guardrails to develop September 22, 2025 21:30
@tgasser-nv tgasser-nv marked this pull request as draft October 13, 2025 14:00
@tgasser-nv
Copy link
Collaborator Author

Converting to draft while I rebase on the latest changes to develop.

@tgasser-nv tgasser-nv force-pushed the chore/type-clean-embeddings branch from 7fa0c6f to 1b6eaab Compare October 14, 2025 19:18
@github-actions
Copy link
Contributor

Documentation preview

https://nvidia-nemo.github.io/Guardrails/review/pr-1383

@codecov-commenter
Copy link

codecov-commenter commented Oct 14, 2025

Codecov Report

❌ Patch coverage is 71.01449% with 20 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
nemoguardrails/embeddings/basic.py 64.51% 11 Missing ⚠️
nemoguardrails/embeddings/cache.py 75.00% 6 Missing ⚠️
...ails/embeddings/providers/sentence_transformers.py 0.00% 2 Missing ⚠️
nemoguardrails/embeddings/providers/nim.py 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@tgasser-nv tgasser-nv marked this pull request as ready for review October 14, 2025 19:58
@tgasser-nv
Copy link
Collaborator Author

Requesting review after rebasing on top of develop and addressing feedback in comments from Pouyan and Traian. cc @Pouyanpi , @trebedea , @cparisien

Copy link
Member

@trebedea trebedea left a comment

Choose a reason for hiding this comment

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

Just a minor comment.

@tgasser-nv tgasser-nv force-pushed the chore/type-clean-embeddings branch from b78de2c to 994cc14 Compare October 24, 2025 20:52
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Overview

Greptile Summary

This PR eliminates 25 Pyright type-checking errors in the nemoguardrails/embeddings/ module by adding explicit type annotations, defensive null-checks, and # type: ignore directives for third-party libraries without type stubs. The changes transform implicitly-typed class attributes in BasicEmbeddingsIndex into explicitly-typed instance attributes initialized in __init__, add graceful-degradation guards to EmbeddingsCache when components are uninitialized, mark optional configuration fields in EmbeddingsCacheConfig, and enable Pyright checking for the entire embeddings directory. These fixes integrate with the existing NeMo-Guardrails architecture by preserving the optional nature of caching and embedding model selection while providing clearer error messages when components fail to initialize, aligning with the project's broader effort to incrementally add static type safety (similar to existing Pyright coverage for rails/, actions/, cli/, kb/, logging/, tracing/).


Important Files Changed

Filename Score Overview
nemoguardrails/embeddings/basic.py 1/5 Critical indentation bug on line 275 will cause unconditional await deadlock in batching code path; needs immediate fix
nemoguardrails/embeddings/cache.py 4/5 Adds null-safety guards, explicit type hints, and graceful degradation when cache components are uninitialized; silent failure may mask configuration issues
nemoguardrails/rails/llm/config.py 5/5 Marks three EmbeddingsCacheConfig fields as Optional to align type signatures with runtime null-handling
pyproject.toml 5/5 Enables Pyright type-checking for nemoguardrails/embeddings/** directory
nemoguardrails/embeddings/providers/fastembed.py 5/5 Adds # type: ignore to suppress missing type stub warning for fastembed import
nemoguardrails/embeddings/providers/nim.py 5/5 Adds # type: ignore to suppress missing type stub warning for langchain_nvidia_ai_endpoints import
nemoguardrails/embeddings/providers/sentence_transformers.py 5/5 Adds # type: ignore comments for sentence_transformers and torch imports
nemoguardrails/embeddings/providers/openai.py 5/5 Adds three # type: ignore comments for openai library imports and version checks

Confidence score: 1/5

  • This PR contains a critical indentation bug that will cause production deadlocks when batching is enabled, making it unsafe to merge in its current state.
  • Score reflects one blocking issue in basic.py line 275 where an await statement is incorrectly unindented, causing unconditional execution regardless of the preceding batch-full check; the remaining changes are sound but overshadowed by this regression.
  • nemoguardrails/embeddings/basic.py lines 267-275 require immediate attention—the await self._current_batch_finished_event.wait() must be re-indented to be inside the if len(self._req_queue) >= self.max_batch_size: block.

Sequence Diagram

sequenceDiagram
    participant User
    participant BasicEmbeddingsIndex
    participant EmbeddingsCache
    participant EmbeddingModel
    participant CacheStore
    participant KeyGenerator

    Note over User,KeyGenerator: Type-Clean Embeddings Flow

    User->>BasicEmbeddingsIndex: __init__(embedding_model, embedding_engine, ...)
    BasicEmbeddingsIndex->>BasicEmbeddingsIndex: Initialize typed instance attributes
    Note right of BasicEmbeddingsIndex: _items: List[IndexItem]<br/>_embeddings: List[List[float]]<br/>_req_queue: Dict[int, str]<br/>_current_batch_full_event: Optional[Event]

    User->>BasicEmbeddingsIndex: add_item(item)
    BasicEmbeddingsIndex->>BasicEmbeddingsIndex: _init_model()
    BasicEmbeddingsIndex->>BasicEmbeddingsIndex: Check if self._model exists
    alt _model is None
        BasicEmbeddingsIndex->>EmbeddingModel: init_embedding_model(model, engine, params)
        EmbeddingModel-->>BasicEmbeddingsIndex: Return model instance or None
        BasicEmbeddingsIndex->>BasicEmbeddingsIndex: Validate model is not None
        alt model is None
            BasicEmbeddingsIndex-->>User: raise ValueError("Couldn't create embedding model")
        end
    end

    BasicEmbeddingsIndex->>BasicEmbeddingsIndex: _get_embeddings([item.text])
    BasicEmbeddingsIndex->>EmbeddingsCache: @cache_embeddings decorator
    EmbeddingsCache->>EmbeddingsCache: Check if cache enabled
    alt cache enabled
        EmbeddingsCache->>EmbeddingsCache: get(texts)
        EmbeddingsCache->>EmbeddingsCache: Check _key_generator and _cache_store not None
        alt key_generator or cache_store is None
            EmbeddingsCache-->>BasicEmbeddingsIndex: return None (graceful degradation)
        else both initialized
            EmbeddingsCache->>KeyGenerator: generate_key(text)
            KeyGenerator-->>EmbeddingsCache: key
            EmbeddingsCache->>CacheStore: get(key)
            CacheStore-->>EmbeddingsCache: cached_value or None
        end
    end

    alt cache miss or disabled
        BasicEmbeddingsIndex->>EmbeddingModel: encode_async(texts)
        EmbeddingModel-->>BasicEmbeddingsIndex: embeddings
        BasicEmbeddingsIndex->>EmbeddingsCache: set(texts, embeddings)
        EmbeddingsCache->>EmbeddingsCache: Check _key_generator and _cache_store not None
        alt both initialized
            EmbeddingsCache->>KeyGenerator: generate_key(text)
            KeyGenerator-->>EmbeddingsCache: key
            EmbeddingsCache->>CacheStore: set(key, value)
        else either is None
            Note right of EmbeddingsCache: Silently skip caching
        end
    end

    BasicEmbeddingsIndex-->>User: Item added successfully

    User->>BasicEmbeddingsIndex: _run_batch()
    BasicEmbeddingsIndex->>BasicEmbeddingsIndex: Check _current_batch_full_event not None
    alt event is None
        BasicEmbeddingsIndex-->>User: raise Exception("event not initialized")
    else event exists
        BasicEmbeddingsIndex->>BasicEmbeddingsIndex: Process batch with event synchronization
    end
Loading

8 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

if not self._current_batch_full_event:
raise Exception("self._current_batch_full_event not initialized")

assert self._current_batch_full_event is not None
Copy link

Choose a reason for hiding this comment

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

style: Redundant check; line 208–209 already raise if _current_batch_full_event is None

Comment on lines 267 to 275
if len(self._req_queue) >= self.max_batch_size:
if not self._current_batch_full_event:
raise Exception("self._current_batch_full_event not initialized")
self._current_batch_full_event.set()

# Wait for the batch to finish
# Wait for the batch to finish
if not self._current_batch_finished_event:
raise Exception("self._current_batch_finished_event not initialized")
await self._current_batch_finished_event.wait()
Copy link

Choose a reason for hiding this comment

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

logic: Indentation issue: line 275 is outside the if block on lines 267–270, so the await always executes regardless of batch size. This will likely deadlock.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@Pouyanpi / @trebedea I'm not familiar with this code, is this a valid bug?

Comment on lines +232 to +235
store_config_raw = d.get("store_config")
store_config: dict = (
store_config_raw if isinstance(store_config_raw, dict) else {}
)
Copy link

Choose a reason for hiding this comment

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

style: Type narrowing with isinstance is good, but d.get('store_config') could be any type from untrusted input. Consider validating the structure beyond just dict type checking.

Comment on lines +256 to +259
@get.register(str)
def _(self, text: str):
if self._key_generator is None or self._cache_store is None:
return None
Copy link

Choose a reason for hiding this comment

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

style: Silently returning None when cache components are uninitialized may hide configuration errors. Consider logging a warning on first occurrence.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Overview

Greptile Summary

This review covers only the changes made since the last review, not the entire PR. The latest changes address three minor type-checking issues in provider files for Google, Cohere, and AzureOpenAI embedding services. Specifically, the developer added # type: ignore directives to suppress Pyright warnings where third-party libraries lack complete type stubs. In google.py, the google.genai import is marked with # type: ignore[import]. In cohere.py, imports are moved into a TYPE_CHECKING block (allowing static analyzers to resolve types without altering runtime behavior), and a # type: ignore[reportCallIssue] is added to the cohere.Client constructor call. In azureopenai.py, a # type: ignore[arg-type] is added where os.getenv() returns str | None but the Azure SDK expects str. All three changes are documentation-only annotations for the type checker and have zero impact on runtime execution. They fit into the broader type-safety cleanup of the nemoguardrails/embeddings/ directory, ensuring the module passes strict Pyright checks while maintaining backward compatibility with the existing lazy-import pattern for optional dependencies.

Important Files Changed

Filename Score Overview
nemoguardrails/embeddings/providers/google.py 5/5 Added # type: ignore[import] to suppress missing type stubs warning for google.genai import.
nemoguardrails/embeddings/providers/cohere.py 5/5 Moved imports into TYPE_CHECKING block and suppressed type-checker warning on cohere.Client call; no runtime logic changed.
nemoguardrails/embeddings/providers/azureopenai.py 4/5 Silenced type-checker warning on azure_endpoint parameter that expects str but receives `str

Confidence score: 4/5

  • This incremental update is safe to merge with very low risk; all changes are type-annotation directives that do not alter runtime behavior.
  • Score is 4/5 instead of 5/5 solely because the azureopenai.py change silences a type mismatch where os.getenv() may return None, and the Azure SDK will fail at runtime if the environment variable is missing—no validation logic is added to catch this earlier.
  • Pay close attention to nemoguardrails/embeddings/providers/azureopenai.py to ensure environment variables are documented as required in deployment guides; no other files require special scrutiny.

3 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Overview

Greptile Summary

This review covers only the changes made since the last review, not the entire PR. The developer has addressed previous feedback by removing redundant None checks that were unreachable after earlier guard clauses, relocating default values from _init_model back into the __init__ constructor to centralize initialization, and eliminating an assert statement in favor of an explicit ValueError. These refinements clean up the defensive programming approach while maintaining the type-safety improvements. However, the critical concurrency bug in _batch_get_embeddings (lines 260–278 of basic.py) remains unresolved: multiple concurrent callers can still create separate batch-event instances, causing some coroutines to await the wrong event and deadlock.

PR Description Notes:

  • Line 208: References to line numbers in the PR body do not match the latest code after refactoring; consider updating the description to reflect the final state.

Important Files Changed

Filename Score Overview
nemoguardrails/embeddings/basic.py 2/5 Moved defaults to constructor; removed redundant checks; concurrency race in _batch_get_embeddings (lines 260–278) remains—multiple coroutines can create separate batch events and deadlock.
nemoguardrails/embeddings/providers/azureopenai.py 4/5 Cleaned up # type: ignore directives; no functional changes.

Confidence score: 2/5

  • This PR remains risky due to an unresolved concurrency bug that can cause deadlocks under concurrent embedding requests.
  • Score reflects the same critical issue as the initial review: the batch-event initialization in _batch_get_embeddings is not thread-safe and can create orphaned events. While the recent changes improved code clarity and removed redundant checks, they did not address the race condition.
  • Pay close attention to nemoguardrails/embeddings/basic.py lines 260–278—this section requires a lock or single-initialization pattern to prevent multiple coroutines from creating conflicting batch events.

2 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +260 to 278
if (
self._current_batch_finished_event is None
or self._current_batch_full_event is None
):
self._current_batch_finished_event = asyncio.Event()
self._current_batch_full_event = asyncio.Event()
self._current_batch_submitted.clear()
asyncio.ensure_future(self._run_batch())

# We check if we reached the max batch size
if len(self._req_queue) >= self.max_batch_size:
if not self._current_batch_full_event:
raise Exception("self._current_batch_full_event not initialized")
self._current_batch_full_event.set()

# Wait for the batch to finish
# Wait for the batch to finish
if not self._current_batch_finished_event:
raise Exception("self._current_batch_finished_event not initialized")
await self._current_batch_finished_event.wait()
Copy link

Choose a reason for hiding this comment

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

logic: Lines 260–267 create new Event objects only if both are None, but line 278 always awaits _current_batch_finished_event regardless of whether this coroutine created the event. If another coroutine set the event between lines 260–267, this await will hang indefinitely waiting for its own request to complete. Is there a lock or other synchronization mechanism ensuring only one coroutine creates the batch events at a time?

try:
from openai import AzureOpenAI
from openai import (
AzureOpenAI, # type: ignore[attr-defined] (Assume this is installed)
Copy link

Choose a reason for hiding this comment

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

style: # type: ignore[attr-defined] is incorrect for this import. AzureOpenAI is a class, not an attribute. If the OpenAI library is installed, this import succeeds without issues. Use # type: ignore without a specifier, or remove it entirely if type stubs are available.

api_key=os.getenv("AZURE_OPENAI_API_KEY"),
api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"), # type: ignore[arg-type] (comes from `$AZURE_OPENAI_ENDPOINT`)
Copy link

Choose a reason for hiding this comment

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

style: The # type: ignore[arg-type] is redundant; os.getenv returns str | None, which AzureOpenAI's constructor should accept. If the constructor requires a non-None value, validate it explicitly rather than silencing the type error. Does the AzureOpenAI constructor accept None for azure_endpoint, or does it require a valid string?

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.

4 participants