Skip to content

LCORE-4710: Implement registry initialization - #3124

Merged
tisnik merged 4 commits into
lightspeed-core:mainfrom
asimurka:initialize-providers-registry
Nov 3, 2026
Merged

tisnik merged 4 commits into
lightspeed-core:mainfrom
asimurka:initialize-providers-registry

Conversation

@asimurka

@asimurka asimurka commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Description

Wire inference provider registry initialization into FastAPI lifespan so configured providers are built and their catalogs loaded before the service serves traffic.

Integration tests for config will be supplied in another PR.

Type of change

  • Refactor
  • New feature
  • Bug fix
  • CVE fix
  • Optimization
  • Documentation Update
  • Configuration Update
  • Bump-up service version
  • Bump-up dependent library [pyproject.toml + uv.lock]
  • Bump-up dependent library [requirements.*.txt for Konflux]
  • Bump-up library or tool used for development (does not change the final image)
  • CI configuration change
  • Konflux configuration change
  • Unit tests improvement
  • Integration tests improvement
  • End to end tests improvement
  • Benchmarks improvement

Tools used to create PR

Identify any AI code assistants used in this PR (for transparency and review context)

  • Assisted-by: Cursor
  • Generated by: N/A

Related Tickets & Documents

Checklist before requesting a review

  • I have performed a self-review of my code.
  • PR has passed all pre-merge test jobs.
  • If it is a core feature, I have added thorough tests.

Testing

Unit

uv run pytest tests/unit/app/test_main_startup.py -q
  • test_lifespan_initializes_inference_registry — OpenAI provider with skip_model_discovery=True; after lifespan startup, registry lists the provider and catalog model chat.
  • test_lifespan_propagates_model_discovery_error — discovery enabled; AsyncModels.list raises APIConnectionError; lifespan raises ModelDiscoveryError and leaves the registry empty.

Summary by CodeRabbit

  • New Features
    • Configured inference providers are initialized as the application starts, making their models available for requests.
  • Bug Fixes
    • Provider discovery failures are surfaced during startup, and failed initialization leaves the provider registry empty.
  • Chores
    • Startup logs now show which inference providers were registered.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 20 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between 28d93dd and cdc5617.

Files ignored due to path filters: 1
  • uv.lock is excluded by !**/*.lock
Files selected for processing: 10
  • pyproject.toml
  • src/providers/inference/azure/provider.py
  • src/providers/inference/base.py
  • src/providers/inference/bedrock/provider.py
  • src/providers/inference/openai/provider.py
  • src/providers/inference/registry.py
  • src/providers/inference/sentence_transformers/model_cache.py
  • src/providers/inference/vertexai/provider.py
  • src/providers/inference/vllm/provider.py
  • src/providers/inference/watsonx/provider.py

Walkthrough

The application lifespan now initializes configured inference providers before OGX client setup. The registry logs the registered provider count and IDs. Unit tests cover successful registration and model discovery failure.

Changes

Inference provider startup

Layer / File(s) Summary
Lifespan initialization and validation
src/app/main.py, src/providers/inference/registry.py, tests/unit/app/test_main_startup.py, tests/unit/app/README.md
The lifespan initializes the registry with inference configuration. The registry logs provider count and IDs. Tests cover provider registration and discovery failure. The README lists the new tests.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Lifespan as FastAPI lifespan
  participant Registry as ProviderRegistry
  participant OpenAI as OpenAI provider
  Lifespan->>Registry: initialize(configuration.inference)
  opt Model discovery enabled
    Registry->>OpenAI: list models
    OpenAI-->>Registry: models or ModelDiscoveryError
  end
Loading

Possibly related PRs

Suggested labels: enhancement, python, Review effort 2/5, risk/moderate

Suggested reviewers: tisnik

Merge Risk: Low · previous review 28d93

Lifecycle re-entry can retain removed providers and leave clients open, and the startup log can be missing. The risk is bounded but warrants follow-up.

Pre-merge checks: Passed 7
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: implementing inference provider registry initialization.
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Performance And Algorithmic Complexity Passed No blocking performance regression found. The pull request adds one startup call to ProviderRegistry.initialize; that method performs a linear pass over configured providers, with no nested per-mode…
Security And Secret Handling Passed No security violation was introduced. The PR adds startup initialization and logs only provider count and local provider IDs in src/providers/inference/registry.py:67-72; it does not log API keys or…
Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 3 functions across 3 files. (1 skipped: 1 unsupported.)

Full details: Performance And Algorithmic Complexity

Explanation

No blocking performance regression found. The pull request adds one startup call to ProviderRegistry.initialize; that method performs a linear pass over configured providers, with no nested per-model queries, unbounded cache, or new list endpoint. The added registry log performs one linear list copy and does not materially affect runtime. Provider discovery uses provider-level listing calls as part of the required startup initialization, not an introduced list-then-query-per-item pattern.

Full details: Security And Secret Handling

Explanation

No security violation was introduced. The PR adds startup initialization and logs only provider count and local provider IDs in src/providers/inference/registry.py:67-72; it does not log API keys or tokens. src/app/main.py:101 adds no endpoint or request handling, so it introduces no missing auth/authz, injection path, or response leak. The API keys in tests/unit/app/test_main_startup.py:73 are dummy test values. No Kubernetes Secret or RH secret manifest changes are present.

Finishing Touches
Generate unit tests (beta)
  • Create a new PR
Simplify code
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

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

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.
Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 4cae323 and 28d93dd.

Files selected for processing: 4
  • src/app/main.py
  • src/providers/inference/registry.py
  • tests/unit/app/README.md
  • tests/unit/app/test_main_startup.py

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Recent review details
Context from checks skipped due to timeout: 27
  • GitHub Check: Red Hat Konflux / rag-content-0-8-e2e-tests / lightspeed-stack-0-8
  • GitHub Check: Red Hat Konflux / lightspeed-core-0-8-enterprise-contract / lightspeed-stack-0-8
  • GitHub Check: Red Hat Konflux / lightspeed-stack-0-8-e2e-tests / lightspeed-stack-0-8
  • GitHub Check: unit_tests (3.12)
  • GitHub Check: unit_tests (3.14)
  • GitHub Check: list_outdated_dependencies
  • GitHub Check: build-pr
  • GitHub Check: unit_tests (3.13)
  • GitHub Check: integration_tests (3.13)
  • GitHub Check: integration_tests (3.12)
  • GitHub Check: ruff
  • GitHub Check: shellcheck
  • GitHub Check: integration_tests (3.14)
  • GitHub Check: dispatch / Harness dispatch
  • GitHub Check: radon
  • GitHub Check: spectral
  • GitHub Check: check_dependencies
  • GitHub Check: Pylinter
  • GitHub Check: bandit
  • GitHub Check: dispatch / Route
  • GitHub Check: Pyright
  • GitHub Check: black
  • GitHub Check: pydocstyle
  • GitHub Check: mypy
  • GitHub Check: Konflux kflux-prd-rh02 / lightspeed-stack-0-8-on-pull-request
  • GitHub Check: authorize / Check repository owner or member
  • GitHub Check: check
Additional context used
Code guidelines: 2
CLAUDE.md — auto-discovered
AGENTS.md — auto-discovered
Path-based instructions: 3
Source excerpt: **Required**: Use pytest for all unit and integration tests **Forbidden**: Do not use unittest - pytest is the standard for this project Source excerpt: **Coverage**: Unit tests require 60% coverage, integration 10%

CodeRabbit inference engine (CLAUDE.md)

Files:

  • tests/unit/app/README.md
  • tests/unit/app/test_main_startup.py
Source excerpt: **Required**: Use pytest for all unit and integration tests Source excerpt: **Forbidden**: Do not use unittest - pytest is the standard for this project Source excerpt: **Coverage**: Unit tests require 60% coverage, integrat...

CodeRabbit inference engine (AGENTS.md)

Files:

  • tests/unit/app/README.md
  • tests/unit/app/test_main_startup.py
Source excerpt: **Fixtures**: Use `conftest.py` for shared fixtures Source excerpt: **Mocking**: `pytest-mock` for AsyncMock objects Source excerpt: **Async tests**: Use marker `pytest.mark.asyncio`

CodeRabbit inference engine (CLAUDE.md)

Files:

  • tests/unit/app/README.md
  • tests/unit/app/test_main_startup.py
Learnings: 6
Learning: 2026-10-31T11:32:30.158Z
Learnt from: CR
Repo: lightspeed-core/lightspeed-stack PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-10-31T11:32:30.158Z
Learning: Source excerpt:
# Lightspeed Core Stack Development Guide

## Code Architecture & Patterns

### Coding Standards

#### Module Standards

- All modules start with descriptive docstrings explaining purpose
- Use `logger = get_logger(__name__)` from `log.py` for module logging
- Package `__init__.py` files contain brief package descriptions
- Central `constants.py` for shared constants with descriptive comments
- Type aliases defined at module level for clarity
- Use Final[type] as type hint for all constants

Applied to files:

  • src/providers/inference/registry.py
Learning: 2026-10-31T11:32:30.158Z
Learnt from: CR
Repo: lightspeed-core/lightspeed-stack PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-10-31T11:32:30.158Z
Learning: Applies to tests/unit/** : Source excerpt:
# Lightspeed Core Stack Development Guide

## Testing Framework

### Unit Tests (pytest)

- **Async tests**: Use marker `pytest.mark.asyncio`

Applied to files:

  • tests/unit/app/test_main_startup.py
Learning: 2026-10-31T11:32:13.138Z
Learnt from: CR
Repo: lightspeed-core/lightspeed-stack PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-10-31T11:32:13.138Z
Learning: Applies to tests/unit/** : Source excerpt:
# Lightspeed Core Stack Development Guide

## Testing Framework

### Unit Tests (pytest)

- **Mocking**: `pytest-mock` for AsyncMock objects

Applied to files:

  • tests/unit/app/test_main_startup.py
Learning: 2026-10-31T11:32:13.138Z
Learnt from: CR
Repo: lightspeed-core/lightspeed-stack PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-10-31T11:32:13.138Z
Learning: Applies to tests/{unit,integration}/** : Source excerpt:
# Lightspeed Core Stack Development Guide

## Testing Framework

### Testing Framework Requirements

- **Forbidden**: Do not use unittest - pytest is the standard for this project

Applied to files:

  • tests/unit/app/test_main_startup.py
Learning: 2026-10-31T11:32:30.158Z
Learnt from: CR
Repo: lightspeed-core/lightspeed-stack PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-10-31T11:32:30.158Z
Learning: Applies to tests/{unit,integration}/** : Source excerpt:
# Lightspeed Core Stack Development Guide

## Testing Framework

### Testing Framework Requirements

- **Required**: Use pytest for all unit and integration tests
- **Forbidden**: Do not use unittest - pytest is the standard for this project

Applied to files:

  • tests/unit/app/test_main_startup.py
Learning: 2026-10-31T11:32:13.138Z
Learnt from: CR
Repo: lightspeed-core/lightspeed-stack PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-10-31T11:32:13.138Z
Learning: Applies to tests/{unit,integration}/** : Source excerpt:
# Lightspeed Core Stack Development Guide

## Testing Framework

### Testing Framework Requirements

- **Required**: Use pytest for all unit and integration tests

Applied to files:

  • tests/unit/app/test_main_startup.py

@asimurka
asimurka marked this pull request as draft November 3, 2026 08:23

@coderabbitai coderabbitai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • Fix comments: Fix CodeRabbit comments on this PR

Comment thread src/app/main.py Resolved
Comment thread src/providers/inference/registry.py Resolved
Comment thread tests/unit/app/test_main_startup.py Resolved
@fullsend-ai-review

fullsend-ai-review Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ⚠️ Cancelled · Started 8:34 AM UTC · Completed 8:45 AM UTC

Commit: 28d93dd · View workflow run →

Runtime: pi · Model: opus → claude-opus-4-6 · Effort: high · Cost: $3.28

This review was superseded by a newer commit. Check the current pull request HEAD's review status before merging.

@asimurka
asimurka marked this pull request as ready for review November 3, 2026 08:47
@fullsend-ai-review

fullsend-ai-review Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 8:48 AM UTC · Ended 8:49 AM UTC

Commit: 85c7922 · View workflow run →

This review was superseded by a newer commit. Check the current pull request HEAD's review status before merging.

@fullsend-ai-review

fullsend-ai-review Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ⚠️ Cancelled · Started 8:56 AM UTC · Completed 9:00 AM UTC

Commit: 11f7c02 · View workflow run →

Runtime: pi · Model: opus → claude-opus-4-6 · Effort: high · Cost: $1.45

This review was superseded by a newer commit. Check the current pull request HEAD's review status before merging.

self._rerankers[provider_model_id] = model
else:
self._embeddings[provider_model_id] = model
self._embeddings[provider_model_id] = cast(EmbeddingModel, model)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Consequence of ST being added as a main dependency

Comment thread pyproject.toml
# Used for Pydantic AI
"pydantic-ai==2.38.0",
"pydantic-ai-skills>=0.11.0,<2.0.0",
# Used by the sentence-transformers inference provider (embedding / rerank)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We need ST to be main dependency

@fullsend-ai-review

fullsend-ai-review Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 9:14 AM UTC · Completed 9:32 AM UTC

Commit: cdc5617 · View workflow run →

Runtime: pi · Model: opus → claude-opus-4-6 · Effort: high · Cost: $5.55

@fullsend-ai-review fullsend-ai-review Bot added the risk/moderate PR risk: moderate label Nov 3, 2026
@fullsend-ai-review

Copy link
Copy Markdown

<!-- fullsend:risk-assessment -->
Risk Assessment: moderate (2/5)

Details

14 files with 264 lines across inference provider modules. Low test ratio is the only elevated signal. Moderate churn on pyproject.toml. Weighted composite 2.

@fullsend-ai-review

Copy link
Copy Markdown

Review

Findings

Medium

  • [scope-bundling] pyproject.toml:89 — The PR promotes sentence-transformers (which transitively pulls in PyTorch/torch) from the ogxlibdev dev dependency group to a main runtime dependency. This is a significant deployment-impacting change (container image size, startup time, memory footprint) that is bundled with the registry wiring work without separate justification in the PR description.
    Remediation: Document in the PR description why sentence-transformers must become a main dependency, or split the dependency promotion into a separate PR with its own rationale and impact analysis.

Low

  • [edge-case] src/providers/inference/registry.py:62 — ProviderRegistry.initialize() has no cleanup on partial failure. If the Nth provider fails during await provider.initialize(), previously-initialized providers remain in _providers, leaving the singleton in a half-initialized state. Currently benign in production (service aborts on failure), but the contract is fragile.
    Remediation: Clear self._providers at the top of initialize() so the method is idempotent.

  • [missing-test] tests/unit/app/test_main_startup.py:170 — No test covers multi-provider partial-failure or empty-providers configuration paths.
    Remediation: Add tests for multi-provider partial failure and empty providers list.

  • [scope-creep] src/providers/inference/sentence_transformers/model_cache.py:72 — The cast(EmbeddingModel, model) change is an unrelated type-narrowing fix not mentioned in the PR description.

  • [stale-doc] docs/devel_doc/providers.md:37 — The sentence-transformers provider row lists sentence-transformers --no-deps as a separate pip dependency, but this PR moves it to main dependencies.
    Remediation: Update the Pip Dependencies column to indicate the package is now bundled.


Labels: New feature PR adding inference provider registry initialization.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Note: The following review comments could not be posted on the diff (GitHub returned 422) and are included here instead:

  • src/providers/inference/registry.py (file-level): Line 62 ·
    [low] edge-case

ProviderRegistry.initialize() has no cleanup on partial failure. If the Nth provider fails during await provider.initialize(), previously-initialized providers remain in _providers, leaving the singleton in a half-initialized state. In production the service aborts on failure so this is currently benign, but the contract is fragile.

Suggested fix: Clear self._providers at the top of initialize() (e.g., self._providers.clear()) so the method is idempotent and any retry starts from a clean slate.

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

See the review comment for full details.

Comment thread pyproject.toml
# Used for Pydantic AI
"pydantic-ai==2.38.0",
"pydantic-ai-skills>=0.11.0,<2.0.0",
# Used by the sentence-transformers inference provider (embedding / rerank)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] scope-bundling

The PR promotes sentence-transformers (which transitively pulls in PyTorch/torch) from the ogxlibdev dev dependency group to a main runtime dependency. This is a significant deployment-impacting change (container image size, startup time, memory footprint) that is bundled with the registry wiring work without separate justification or discussion in the PR description.

Suggested fix: Document in the PR description why sentence-transformers must become a main dependency, or split the dependency promotion into a separate PR with its own rationale and impact analysis.

Comment thread tests/unit/app/test_main_startup.py Resolved

@tisnik tisnik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@tisnik
tisnik merged commit fa901c9 into lightspeed-core:main Nov 3, 2026
139 of 141 checks passed
@fullsend-ai-retro

fullsend-ai-retro Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 12:03 PM UTC · Completed 12:14 PM UTC

Commit: cdc5617 · View workflow run →

Runtime: pi · Model: opus → claude-opus-4-6 · Effort: high · Cost: $2.95

@fullsend-ai-retro

Copy link
Copy Markdown

Retro: PR #3124 — LCORE-4710: Implement registry initialization

Timeline

  1. 08:06 UTC — Author (asimurka) pushed commit 28d93dd "Implement registry initialization" (co-authored with Cursor).
  2. 08:14 UTC — First review dispatch triggered on 28d93dd.
  3. 08:23 UTC — CodeRabbit reviewed, finding a logger import issue (logging.getLogger vs project get_logger).
  4. 08:34–08:45 UTC — First review agent run cancelled (superseded by new commit). Cost: $3.28.
  5. 08:43 UTC — Commit 85c7922 pushed ("Make sentence-transformers a main dependency"). Second review dispatched, immediately cancelled.
  6. 08:46 UTC — Commit 11f7c02 pushed ("Fixed logger import" — addressing CodeRabbit's finding). Third review dispatched.
  7. 08:47–08:56 UTC — Third review cancelled (superseded). Cost: $1.45.
  8. 08:54 UTC — Commit cdc5617 pushed ("Fix mypy issue"). Fourth review dispatched.
  9. 09:14–09:32 UTC — Fourth review completed successfully. Cost: $5.55. Posted CHANGES_REQUESTED with 5 findings.
  10. 11:43 UTC — Human reviewer (tisnik) approved with "LGTM".
  11. 11:55 UTC — PR merged with agent's CHANGES_REQUESTED unresolved.

Total review agent cost: ~$10.28 (3 cancelled runs: ~$4.73 wasted; 1 successful run: $5.55).

Evidence for existing issues

Autonomy assessment

The human reviewer approved with "LGTM" and no inline comments. Per the autonomy-readiness methodology, the delta between agent and human review is inconclusive — silent approval means the human found nothing to flag, but we cannot infer that the agent matched or exceeded human review from this single PR.

Proposals filed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants