feat(client): NemoClient platform provider + request-scoped FastAPI DI#800
feat(client): NemoClient platform provider + request-scoped FastAPI DI#800maxdubrinsky wants to merge 5 commits into
Conversation
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
…-fastapi-di/md Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
|
📝 WalkthroughWalkthroughNemo client creation now resolves pluggable providers through entry points or explicit overrides. nmp-common supplies a platform provider with routing, headers, workspace support, and shared transports. Service dependencies expose request-scoped clients with synchronized lifecycle management. ChangesNemo client provider flow
Sequence Diagram(s)sequenceDiagram
participant ServiceRequest
participant FastAPI
participant DependencyProvider
participant PlatformNemoClientProvider
participant AsyncNemoClient
ServiceRequest->>FastAPI: resolve get_nemo_client
FastAPI->>DependencyProvider: request-scoped client dependency
DependencyProvider->>PlatformNemoClientProvider: create async client
PlatformNemoClientProvider->>AsyncNemoClient: construct with workspace, headers, and router
AsyncNemoClient-->>FastAPI: return request-scoped client
FastAPI-->>ServiceRequest: inject client
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/nemo_platform_plugin/src/nemo_platform_plugin/client_provider.py (1)
187-253: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract shared entry-point resolution helper.
_resolve_provideris duplicated verbatim between the two files (dedup, deterministic-conflict RuntimeError, load/construct, protocol validation) — only the group name, protocol type, and default class differ. One shared helper avoids future divergence when either copy gets a bug fix, and is a natural place to add a lock around the scan+load+construct+cache sequence.
packages/nemo_platform_plugin/src/nemo_platform_plugin/client_provider.py#L187-L253: replace with a call to a shared_resolve_provider(group, protocol, default_factory, kind_label)helper.packages/nemo_platform_plugin/src/nemo_platform_plugin/sdk_provider.py#L298-L337: replace with a call to the same shared helper, passing"nemo.sdk_provider",SDKProvider,DefaultSDKProvider.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/nemo_platform_plugin/src/nemo_platform_plugin/client_provider.py` around lines 187 - 253, Extract the duplicated entry-point resolution logic from _resolve_provider in packages/nemo_platform_plugin/src/nemo_platform_plugin/client_provider.py#L187-L253 and packages/nemo_platform_plugin/src/nemo_platform_plugin/sdk_provider.py#L298-L337 into one shared _resolve_provider(group, protocol, default_factory, kind_label) helper. Preserve deterministic conflict detection, entry-point loading and construction, protocol validation, default fallback, caching, and add locking around the scan/load/construct/cache sequence; update both providers to call it with their respective group, protocol, and default factory.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/nemo_platform_plugin/src/nemo_platform_plugin/client_provider.py`:
- Around line 187-253: Extract the duplicated entry-point resolution logic from
_resolve_provider in
packages/nemo_platform_plugin/src/nemo_platform_plugin/client_provider.py#L187-L253
and
packages/nemo_platform_plugin/src/nemo_platform_plugin/sdk_provider.py#L298-L337
into one shared _resolve_provider(group, protocol, default_factory, kind_label)
helper. Preserve deterministic conflict detection, entry-point loading and
construction, protocol validation, default fallback, caching, and add locking
around the scan/load/construct/cache sequence; update both providers to call it
with their respective group, protocol, and default factory.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 72cf3fb6-a3a0-4a76-b118-1f0adb68251b
📒 Files selected for processing (14)
packages/nemo_platform/pyproject.tomlpackages/nemo_platform_plugin/src/nemo_platform_plugin/client_provider.pypackages/nemo_platform_plugin/src/nemo_platform_plugin/dependencies.pypackages/nemo_platform_plugin/src/nemo_platform_plugin/sdk_provider.pypackages/nemo_platform_plugin/tests/test_client_provider.pypackages/nemo_platform_plugin/tests/test_dependencies.pypackages/nemo_platform_plugin/tests/test_sdk_provider.pypackages/nmp_common/pyproject.tomlpackages/nmp_common/src/nmp/common/client_factory.pypackages/nmp_common/src/nmp/common/service/__init__.pypackages/nmp_common/src/nmp/common/service/base.pypackages/nmp_common/src/nmp/common/service/dependencies.pypackages/nmp_common/tests/client_factory/test_client_factory.pypackages/nmp_common/tests/nmp_common/test_common_service.py
Summary
Consolidates the NemoClient foundation into one PR: the platform provider (AIRCORE-883) plus the request-scoped FastAPI DI seam (AIRCORE-904). This was previously split across #799 (provider) and #800 (DI, stacked on #799's branch). #800 is now retargeted to
mainand carries both halves; #799 is closed in favor of this PR.Provider foundation (AIRCORE-883)
NemoClientProviderprotocol with explicit override, entry-point discovery, and a zero-nmp-commonenv-var default (DefaultNemoClientProvider).PlatformNemoClientProvider) backed by per-service URL routing, shared HTTP transports, request principal headers, and OTEL propagation.nmp-commonand the bundlednemo-platformpackage.Request-scoped DI (AIRCORE-904)
get_nemo_clientdependency + exact common-package re-export.AsyncNemoClientwith current principal + trace headers, sharing one provider-owned transport.DependencyProvidertransport/SDK init made thread-safe and order-independent; provider-owned transport closed exactly once on shutdown.How it's used (downstream)
In-process (service / middleware / controller), async:
In a job's task container the same call falls back to the env-var
DefaultNemoClientProvider(NMP_BASE_URL/NMP_PRINCIPALinjected by the jobs backend). The plugin imports onlynemo_platform_plugin.client_provider— nevernmp-common, never Stainless.Per-service migration playbook:
packages/nemo_platform_plugin/src/nemo_platform_plugin/client/MIGRATION.md.Unblocks
client_from_platform(...)forDepends(get_nemo_client).endpoints.py), AIRCORE-893 (CLI generator → typed clients).Follow-up (not in this PR)
client_clsparam soget_async_nemo_client(AsyncFilesClient)returns a typed client directly (today it returns a base client; use.send(endpoints.*)).close()/ context-manager support — AIRCORE-933.Validation
git diff --check, focusedty, and wheel entry-point inspection passed. Independent adversarial review found no blocker on either half.main(while stacked on a feature branch, most CI jobs were suppressed).Linear: https://linear.app/nvidia/issue/AIRCORE-883 , https://linear.app/nvidia/issue/AIRCORE-904
Summary by CodeRabbit
New Features
Bug Fixes
Tests