Skip to content

feat(client): add pagination, retry, and client-side options to NemoClient#454

Merged
matthewgrossman merged 13 commits into
mainfrom
mgrossman/aircore-828-add-first-class-auth-support-to-nemoclient-replace
Jun 25, 2026
Merged

feat(client): add pagination, retry, and client-side options to NemoClient#454
matthewgrossman merged 13 commits into
mainfrom
mgrossman/aircore-828-add-first-class-auth-support-to-nemoclient-replace

Conversation

@matthewgrossman

@matthewgrossman matthewgrossman commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Extends the NemoClient typed HTTP client with three features: automatic pagination, configurable retry, and client-side endpoint options.

Linked issue: AIRCORE-843

What changed

Paginated[T] — automatic pagination via return type marker

Endpoints declare -> Paginated[Item] and the client automatically iterates all pages, mirroring the existing Stream[T] pattern:

@get("/apis/example/v2/workspaces/{workspace}/items")
def list_items(*, workspace: str | None = None) -> Paginated[ExampleItem]: ...

# Auto-iterate all pages
for item in client.list_items():
    print(item.name)

# Single page with metadata
page = client.list_items().data()
print(f"Page {page.page} of {page.total_pages}")
  • Default OffsetPagination strategy matches the standard NemoListResponse envelope
  • Custom strategies via subclass: -> Paginated[Item, MyPagination]
  • PaginationStrategy protocol for extensibility
  • PageResult[T] dataclass with items + metadata for single-page access
  • Subsequent page fetches share the client's retry policy

RetryPolicy — configurable retry with exponential backoff

# Client-level default
client = ExampleClient(base_url="...", retry=RetryPolicy(max_retries=3))

# Per-request override
client.send(endpoint_fn(...), retry=RetryPolicy(max_retries=10))
  • Retries on configurable status codes (default: 502, 503, 504, 429) and transport errors
  • Shared _should_retry decision logic across sync/async paths
  • Page fetchers also retry with the same policy

Blessed client-side options (exist_ok)

Endpoint signatures can include blessed parameter names that control client behavior without being sent over the wire:

@post("/apis/example/v2/workspaces/{workspace}/items")
def create_item(*, body: CreateRequest, exist_ok: bool = False) -> Item: ...

client.create_item(body=req, exist_ok=True)  # swallows 409 Conflict
  • BLESSED_CLIENT_PARAMS / RESERVED_PARAM_NAMES registries in types.py
  • Decoration-time validation: unknown params raise TypeError at import time
  • Type validation: blessed params must have the expected annotation
  • Applied in send() so both client.send() and client.method() paths work

EndpointMethod typing for all response types

method() overloads now return correctly-typed descriptors for every response-type marker:

Endpoint return type method() descriptor returns
BinaryContent NemoBinaryResponse / AsyncNemoBinaryResponse
Stream[T] NemoStreamResponse[T] / AsyncNemoStreamResponse[T]
Paginated[T] NemoPaginatedResponse[T] / AsyncNemoPaginatedResponse[T]
None NemoResponse[None]
BaseModel NemoResponse[T]

Architecture

types.py      — Paginated[T,S], PaginationStrategy, OffsetPagination,
                RESERVED_PARAM_NAMES, BLESSED_CLIENT_PARAMS, RetryPolicy
endpoint.py   — decoration-time validation + type checking of blessed params,
                strips client options into PreparedRequest.client_options
client.py     — send() dispatches by response type, _should_retry shared
                decision logic, _request_with_retry, _apply_client_options,
                _make_page_fetcher
response.py   — NemoPaginatedResponse / AsyncNemoPaginatedResponse,
                PageResult, SyncPageFetcher / AsyncPageFetcher
method.py     — EndpointMethod[P, SyncReturnT, AsyncReturnT] with
                method() overloads per response-type marker

Test plan

  • exist_ok stripping from request, 409 swallowing (sync + async, via send + method)
  • Decoration-time param validation (unknown params, blessed params, type checking)
  • RetryPolicy (503 retry, exhaustion, non-retryable status, transport errors, per-request override)
  • Pagination (single page, multi-page, empty, no metadata, custom strategy, retry on subsequent pages)
  • PageResult.data() with metadata (sync + async)
  • method() descriptor returns correct types for paginated endpoints
  • All existing client tests pass (27 pre-existing + 44 new = 71 total)

🤖 Generated with Claude Code

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
…upport-to-nemoclient-replace

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
@matthewgrossman matthewgrossman requested review from a team as code owners June 25, 2026 03:22
@github-actions github-actions Bot added the feat label Jun 25, 2026
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Typed client support now includes paginated responses, retry policies, and client-side options like exist_ok. Endpoint preparation stores client options separately from request data, and the example plugin switches its typed list endpoint to Paginated[ExampleItem].

Changes

Client pagination, retries, and client options

Layer / File(s) Summary
Shared client contracts
packages/nemo_platform_plugin/src/nemo_platform_plugin/client/types.py
Adds pagination strategy types, Paginated, RetryPolicy, blessed client parameters, and PreparedRequest.client_options.
Endpoint client-option binding
packages/nemo_platform_plugin/src/nemo_platform_plugin/client/endpoint.py, packages/nemo_platform_plugin/tests/client/test_client_options.py
Validates endpoint signatures, strips blessed options from request construction, stores them on PreparedRequest.client_options, and covers exist_ok plus signature validation cases.
Paginated response wrappers
packages/nemo_platform_plugin/src/nemo_platform_plugin/client/response.py
Adds sync and async paginated response wrappers that parse page JSON, validate items, and fetch later pages through a strategy callback.
Sync client send path
packages/nemo_platform_plugin/src/nemo_platform_plugin/client/client.py, packages/nemo_platform_plugin/tests/client/test_pagination.py, packages/nemo_platform_plugin/tests/client/test_client_options.py
Extends sync client send for per-call retry overrides, paginated responses, page fetchers, and backoff retries; adds sync pagination and retry coverage.
Async client send path
packages/nemo_platform_plugin/src/nemo_platform_plugin/client/client.py, packages/nemo_platform_plugin/tests/client/test_pagination.py, packages/nemo_platform_plugin/tests/client/test_client_options.py
Adds async retry handling and paginated send flow, with async pagination and retry tests.
Example endpoint contract
plugins/example-plugin/src/nemo_example_plugin/types/endpoints.py
Switches the example list endpoint to Paginated[ExampleItem] and adds exist_ok to create_item.

Possibly related PRs

Suggested reviewers

  • maxdubrinsky
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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.
Title check ✅ Passed The title accurately summarizes the main client changes: pagination, retry, and client-side options.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mgrossman/aircore-828-add-first-class-auth-support-to-nemoclient-replace

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

@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.

Actionable comments posted: 5

🧹 Nitpick comments (3)
packages/nemo_platform_plugin/tests/client/test_pagination.py (1)

6-6: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove postponed annotations here.

This new test file does not need stringified annotations. As per coding guidelines, “Always prefer concrete type hints over string-based ones in Python code.”

🤖 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/tests/client/test_pagination.py` at line 6, The
new test module is unnecessarily using postponed annotations, so remove the
__future__ import in the test file and keep the type hints concrete. Update the
test module around the top-level imports in test_pagination.py so it follows the
guideline of preferring normal type annotations over stringified ones.

Source: Coding guidelines

packages/nemo_platform_plugin/src/nemo_platform_plugin/client/response.py (1)

284-284: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Hardcoded current_page=1 breaks the documented cursor (str) pagination.

Lines 224-225 advertise str page values for cursor-based strategies, but the first next_page(body, 1) call passes an int. Any non-offset strategy gets a wrong initial page. Derive the starting page from the parsed body (or the strategy) instead of literal 1.

Also applies to: 339-339

🤖 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/response.py` at
line 284, The pagination flow in `Response.next_page` is hardcoding
`current_page` as `1`, which breaks cursor-based strategies that expect the
documented `str` page value. Update the `next_page` call sites in `Response` to
derive the initial/current page from the parsed response body or the strategy
itself instead of passing a literal `1`, so non-offset strategies receive the
correct type and value.
packages/nemo_platform_plugin/src/nemo_platform_plugin/client/types.py (1)

145-150: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

BLESSED_CLIENT_PARAMS type values are dead and the comment misleads.

The comment says each entry maps to its "expected Python type," but endpoint._identify_client_option_params only reads .keys(). A mis-annotated exist_ok: str passes validation silently. Either validate against the type or drop it to a frozenset.

🤖 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/types.py`
around lines 145 - 150, BLESSED_CLIENT_PARAMS is treating the values as if they
matter, but endpoint._identify_client_option_params only uses the keys, so the
current type mapping is misleading and can silently allow bad annotations.
Update the client-option validation to either actually check the annotated type
against the expected Python type for each entry, or replace
BLESSED_CLIENT_PARAMS with a key-only structure like a frozenset if only
membership is needed. Keep the fix centered around BLESSED_CLIENT_PARAMS and
endpoint._identify_client_option_params so the declared contract matches the
behavior.
🤖 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.

Inline comments:
In `@packages/nemo_platform_plugin/src/nemo_platform_plugin/client/client.py`:
- Around line 318-332: The retry loop in client handling is replaying every
request, which can duplicate non-idempotent writes or resend exhausted bodies
after failures. Update the retry logic in the request-sending path around the
_send_once call to only retry replay-safe operations, using method/idempotency
checks or an explicit opt-in/idempotency key before entering the retry loop.
Apply the same guard to the related retry block in the other affected section so
only safe requests can back off and retry.
- Around line 283-287: The paginated request path in NemoClient currently
bypasses the retry logic, so first-page and later-page 503s are not handled by
the configured policy. Update the paginated flow in NemoClient’s request
handling and page fetcher creation so that both the initial page and subsequent
page requests go through the same retry-aware path used by _send_with_retry, and
ensure NemoPaginatedResponse receives a fetcher that preserves retry behavior
for each page request. Apply the same fix anywhere the affected paginated
request helpers are used so all pagination paths share consistent retry
handling.
- Around line 205-211: The paginated send overload is too narrow because
`PreparedRequest[Paginated[ModelT]]` only covers the default pagination
strategy, causing custom paginated requests to miss the `NemoPaginatedResponse`
return type. Update the `send` overloads in the client API so they accept
`PreparedRequest[Paginated[ModelT, Any]]` or add a second strategy type
parameter for both the sync and async variants, keeping the overloads aligned
with `NemoPaginatedResponse` and the generic `Paginated` model.

In `@packages/nemo_platform_plugin/tests/client/test_pagination.py`:
- Around line 149-150: The pagination test assertion is too permissive because
the fallback allows non-dict request arguments to pass without checking page 2;
tighten the check in the test around mock_http.request.call_args_list so it
explicitly verifies the second call includes params and that the page value is
2, using second_call_params as the key reference and failing the assertion when
params are missing or not a dict.

In `@plugins/example-plugin/src/nemo_example_plugin/types/endpoints.py`:
- Around line 39-41: The `list_items` endpoint signature in `ExamplePlugin`
dropped the `query_params` support even though the route still accepts `filter`,
`page_size`, and `sort`. Update the abstract `list_items` method to keep a
`query_params` argument (alongside `workspace`) and preserve the ability to pass
these server-side filters through the SDK, matching the existing endpoint
contract in the endpoints types.

---

Nitpick comments:
In `@packages/nemo_platform_plugin/src/nemo_platform_plugin/client/response.py`:
- Line 284: The pagination flow in `Response.next_page` is hardcoding
`current_page` as `1`, which breaks cursor-based strategies that expect the
documented `str` page value. Update the `next_page` call sites in `Response` to
derive the initial/current page from the parsed response body or the strategy
itself instead of passing a literal `1`, so non-offset strategies receive the
correct type and value.

In `@packages/nemo_platform_plugin/src/nemo_platform_plugin/client/types.py`:
- Around line 145-150: BLESSED_CLIENT_PARAMS is treating the values as if they
matter, but endpoint._identify_client_option_params only uses the keys, so the
current type mapping is misleading and can silently allow bad annotations.
Update the client-option validation to either actually check the annotated type
against the expected Python type for each entry, or replace
BLESSED_CLIENT_PARAMS with a key-only structure like a frozenset if only
membership is needed. Keep the fix centered around BLESSED_CLIENT_PARAMS and
endpoint._identify_client_option_params so the declared contract matches the
behavior.

In `@packages/nemo_platform_plugin/tests/client/test_pagination.py`:
- Line 6: The new test module is unnecessarily using postponed annotations, so
remove the __future__ import in the test file and keep the type hints concrete.
Update the test module around the top-level imports in test_pagination.py so it
follows the guideline of preferring normal type annotations over stringified
ones.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6477ef84-7cc9-4aa5-8b32-48180ad7ad67

📥 Commits

Reviewing files that changed from the base of the PR and between b4473e8 and 6ee1880.

📒 Files selected for processing (7)
  • packages/nemo_platform_plugin/src/nemo_platform_plugin/client/client.py
  • packages/nemo_platform_plugin/src/nemo_platform_plugin/client/endpoint.py
  • packages/nemo_platform_plugin/src/nemo_platform_plugin/client/response.py
  • packages/nemo_platform_plugin/src/nemo_platform_plugin/client/types.py
  • packages/nemo_platform_plugin/tests/client/test_client_options.py
  • packages/nemo_platform_plugin/tests/client/test_pagination.py
  • plugins/example-plugin/src/nemo_example_plugin/types/endpoints.py

Comment thread packages/nemo_platform_plugin/src/nemo_platform_plugin/client/client.py Outdated
Comment thread packages/nemo_platform_plugin/src/nemo_platform_plugin/client/client.py Outdated
Comment thread packages/nemo_platform_plugin/tests/client/test_pagination.py Outdated
Comment thread plugins/example-plugin/src/nemo_example_plugin/types/endpoints.py Outdated
@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 21161/27751 76.2% 61.4%
Integration Tests 12213/26520 46.1% 19.5%

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>

@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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@packages/nemo_platform_plugin/src/nemo_platform_plugin/client/client.py`:
- Around line 287-288: The paginated response path in NemoClient is dropping the
caller’s resolved retry policy, so later page fetches and the first page’s
retryable-status handling do not consistently use the same behavior. Update the
send/_send_once flow so the effective retry policy is passed through to
_send_once and used when constructing the lazy page fetcher via
_make_page_fetcher, and extend the retryable-status check in the send helpers to
treat NemoPaginatedResponse and AsyncNemoPaginatedResponse the same as
NemoResponse; apply the same fix in all matching sync and async send variants.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 638bb59f-97e4-4094-849a-af121bcaa18b

📥 Commits

Reviewing files that changed from the base of the PR and between b631148 and b111e0f.

📒 Files selected for processing (1)
  • packages/nemo_platform_plugin/src/nemo_platform_plugin/client/client.py

Comment thread packages/nemo_platform_plugin/src/nemo_platform_plugin/client/client.py Outdated
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>

@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.

🧹 Nitpick comments (2)
packages/nemo_platform_plugin/src/nemo_platform_plugin/client/response.py (2)

285-285: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Parameterize the dict return type.

tuple[list[ModelT], dict]tuple[list[ModelT], dict[str, Any]]. Applies to the async twin at line 343 too.

As per coding guidelines: "Always prefer concrete type hints over string-based ones in Python code".

🤖 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/response.py` at
line 285, The return type for _parse_page is using an unparameterized dict, so
update it to a concrete mapping type and mirror the same change in the async
twin method later in the class. Adjust the annotation on _parse_page (and the
corresponding async parser) from tuple[list[ModelT], dict] to
tuple[list[ModelT], dict[str, Any]] so the response shape is fully typed and
consistent with the coding guidelines.

Source: Coding guidelines


343-360: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Duplicated _parse_page and data across sync/async wrappers.

These two methods are byte-identical to NemoPaginatedResponse (lines 285-302). Extract into a shared base mixin to avoid drift.

♻️ Sketch
class _BasePaginatedResponse(Generic[ModelT]):
    _first_response: httpx.Response
    _model_type: type[ModelT]
    _strategy: type[PaginationStrategy]

    `@property`
    def http_response(self) -> httpx.Response:
        return self._first_response

    def _parse_page(self, raw: httpx.Response) -> tuple[list[ModelT], dict[str, Any]]:
        raw.raise_for_status()
        body = raw.json()
        items = [self._model_type.model_validate(i) for i in self._strategy.extract_items(body)]
        return items, body

    def data(self) -> PageResult[ModelT]:
        items, body = self._parse_page(self._first_response)
        pagination = body.get("pagination") or {}
        return PageResult(
            items=items,
            page=pagination.get("page"),
            page_size=pagination.get("page_size"),
            total_pages=pagination.get("total_pages"),
            total_results=pagination.get("total_results"),
        )
🤖 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/response.py`
around lines 343 - 360, The _parse_page and data methods on this paginated
response wrapper are duplicated with NemoPaginatedResponse, so move the shared
parsing/metadata logic into a common base mixin or base class and have both
sync/async wrappers inherit it. Keep the shared behavior in a single
implementation that uses _first_response, _model_type, and _strategy, and let
both response classes reuse the same http_response property and PageResult
construction to prevent drift.
🤖 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/response.py`:
- Line 285: The return type for _parse_page is using an unparameterized dict, so
update it to a concrete mapping type and mirror the same change in the async
twin method later in the class. Adjust the annotation on _parse_page (and the
corresponding async parser) from tuple[list[ModelT], dict] to
tuple[list[ModelT], dict[str, Any]] so the response shape is fully typed and
consistent with the coding guidelines.
- Around line 343-360: The _parse_page and data methods on this paginated
response wrapper are duplicated with NemoPaginatedResponse, so move the shared
parsing/metadata logic into a common base mixin or base class and have both
sync/async wrappers inherit it. Keep the shared behavior in a single
implementation that uses _first_response, _model_type, and _strategy, and let
both response classes reuse the same http_response property and PageResult
construction to prevent drift.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: e142f4ff-e231-4393-b79e-4534fa35af07

📥 Commits

Reviewing files that changed from the base of the PR and between b111e0f and c25ed74.

📒 Files selected for processing (4)
  • packages/nemo_platform_plugin/src/nemo_platform_plugin/client/client.py
  • packages/nemo_platform_plugin/src/nemo_platform_plugin/client/endpoint.py
  • packages/nemo_platform_plugin/src/nemo_platform_plugin/client/response.py
  • packages/nemo_platform_plugin/tests/client/test_pagination.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/nemo_platform_plugin/src/nemo_platform_plugin/client/endpoint.py

matthewgrossman and others added 7 commits June 25, 2026 09:22
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
…upport-to-nemoclient-replace

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
list_items now returns Paginated[ExampleItem] instead of
ExampleItemPage.  Update tests to use PageResult.items instead of
.data, and remove the query_params test since pagination is now
handled internally by the client.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
EndpointMethod.__get__ always returned Callable[P, NemoResponse[ResponseT]],
which meant Paginated endpoints returned NemoResponse[Paginated[...]] to
the type checker instead of NemoPaginatedResponse[T]. This caused ty to
reject .data().items on paginated responses.

Add PaginatedEndpointMethod descriptor that returns NemoPaginatedResponse[T],
and overload method() to select it automatically for Paginated endpoints.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
@matthewgrossman matthewgrossman changed the title feat(client): Add pagination and exist_ok to nemoclient feat(client): add pagination, retry, and client-side options to NemoClient Jun 25, 2026

@maxdubrinsky maxdubrinsky 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.

Looks good, left a note for future us

Comment thread plugins/example-plugin/src/nemo_example_plugin/types/endpoints.py
@matthewgrossman matthewgrossman added this pull request to the merge queue Jun 25, 2026
Merged via the queue into main with commit 3a7b0ed Jun 25, 2026
53 checks passed
@matthewgrossman matthewgrossman deleted the mgrossman/aircore-828-add-first-class-auth-support-to-nemoclient-replace branch June 25, 2026 20:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants