Skip to content

feat: add the models namespace to the existing client - #69

Merged
mattmillerai merged 1 commit into
mainfrom
matt/be-8491-models-namespace
Aug 23, 2026
Merged

feat: add the models namespace to the existing client#69
mattmillerai merged 1 commit into
mainfrom
matt/be-8491-models-namespace

Conversation

@mattmillerai

Copy link
Copy Markdown
Contributor

ELI-5

The client you already build (Comfy(...) / AsyncComfy(...)) now has a models drawer on it: client.models. It is a drawer in the same cabinet, not a second cabinet — it uses the client's key, its address, its connection pool and its timeout, and if you change one of those on the client afterwards the drawer sees the change immediately.

What changed

  • New client.models namespace on both Comfy and AsyncComfy (src/comfy_sdk/models.py: Models / AsyncModels). It is constructed by the client with the client's own transport, so credentials, base URL, connection pool and timeout are shared rather than duplicated.
  • Read-only view of the shared configmodels.base_url and models.timeout read through to the live transport, so a post-construction change on the client (rotated key, new timeout) is visible through models with nothing to re-sync.
  • base_url / timeout properties on ComfyLow and AsyncComfyLow so the layer above reports that configuration without reaching into private attributes. Additive and read-only; neither name was previously an attribute on either transport (only _p, _own_client, _client are set in __init__), so nothing is shadowed or overridden.
  • Docs — a ## The models namespace section in the README plus module/class docstrings.
  • Tests — a new tests/test_models_namespace.py (13 tests) and the new Models/AsyncModels pair added to the sync/async public-surface parity guard.

Why a namespace and not a second client

A separate client object for model operations would fork credential handling, base URL resolution, transport and retry/timeout configuration — four things that would then have to be kept in agreement. Holding the host client's transport object by identity makes that impossible by construction, which is what the tests assert (client.models._low is client._low, plus a live timeout change and a live credential rotation both observed through models).

Scope

This adds the namespace and its shared configuration only. A model-run method, credential resolution, exception mapping and retry policy are each separate follow-on work and are deliberately absent here. No dead-end was added for them: there is no stub method that raises "not supported" — the attribute simply does not exist yet, so nothing in this diff denies a capability or has to be falsified. Sizing the part not covered here: the vendored contract this SDK is generated from and typed against (spec/openapi.yaml, spec/VERSION 2.0.0) declares 11 operationIds, 0 of which are model routes, so a model method could not be typed against a committed contract in this change even if it were in scope.

Judgment calls

  1. Nothing added to the top-level package surface. Models / AsyncModels are not exported from comfy_sdk and are not in __all__, so from comfy_sdk import Comfy remains the only import a caller needs; the namespace is reached as client.models. That is a deliberate departure from AssetFactory / WorkflowFactory, which are exported — this requirement asked for no new caller-facing import path. A test guards it. The implementation module comfy_sdk.models necessarily exists (any implementation needs a module) but is not part of the documented surface; annotating the type is comfy_sdk.models.Models.
  2. _ModelsBase._low is typed as the sync-or-async union, with each subclass's constructor pinning the concrete transport. Narrowing the attribute per subclass is a mypy override error; the constructor signatures are what enforce the pairing today, and a future sync/async method narrows locally.
  3. models.timeout returns httpx.Timeout, the transport's live value, rather than the float | None passed to the constructor — the constructor value is not retained anywhere, and httpx is already part of this SDK's public surface elsewhere.

Not exercised here

The specification and design documents that settle this namespace's name and its placement inside the existing client live in an internal tool that is not reachable from the environment this was built in, as do the related tracker issues; those requirements were taken as given rather than re-read at the source, and nothing in this diff depends on an unread detail of them beyond the namespace's name and the on-the-existing-client constraint. Everything verifiable locally — the client construction path, both transports, the vendored spec, the full test suite and every CI gate — was exercised, below.

Provenance

  • Authored by: agent-work loop
  • Verified: ruff check . clean; ruff format --check . clean (44 files); mypy src no issues in 17 files; pytest 180 passed / 4 skipped; scripts/check_drift.py models in sync with the spec; scripts/check_public_repo_hygiene.py clean
  • Deviations: none against the requirements in scope; the three judgment calls above are the only places a reasonable alternative existed

Model operations get a namespace on the client integrators already
construct — client.models on both Comfy and AsyncComfy — instead of a
second client object, which would fork credential handling, base URL,
transport and timeout configuration.

The namespace holds the host client's transport itself rather than a copy
of its settings, so a change made on the client after construction (a
rotated key, a different timeout) applies through models with no
re-wiring. It exposes that shared configuration read-only as base_url and
timeout, backed by new read-only properties of the same names on both
comfy_low transports so the layer above does not have to reach into
private attributes.

Nothing is added to the top-level package: from comfy_sdk import Comfy
stays the only entry point and client.models is the whole surface. The
sync/async parity guard gains the new pair, and the README documents the
namespace.
@mattmillerai mattmillerai added the agent-coded Authored by the agent-work loop label Aug 23, 2026
@mattmillerai
mattmillerai marked this pull request as ready for review August 23, 2026 04:53
@mattmillerai
mattmillerai requested review from a team as code owners August 23, 2026 04:53
@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your current included review allowance is based on your included PR review attempts over the past 7 days.

Next review available in: 37 minutes

Limit details: You’ve used the included review currently available. Your 102 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4862c819-939f-44c4-8571-854b25ba5721

📥 Commits

Reviewing files that changed from the base of the PR and between 454b2b6 and 44360ed.

📒 Files selected for processing (6)
  • README.md
  • src/comfy_low/transport.py
  • src/comfy_sdk/client.py
  • src/comfy_sdk/models.py
  • tests/test_models_namespace.py
  • tests/test_sync_async_parity.py

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

@mattmillerai mattmillerai added cursor-review Request an automated Cursor review full-autonomy Approved AI-brownfield: merges on machine gates alone, no human approver. Design doc + flag req'd. labels Aug 23, 2026
@mattmillerai
mattmillerai merged commit 2e6dc46 into main Aug 23, 2026
11 checks passed
@mattmillerai
mattmillerai deleted the matt/be-8491-models-namespace branch August 23, 2026 22:29
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 23, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

agent-coded Authored by the agent-work loop cursor-review Request an automated Cursor review full-autonomy Approved AI-brownfield: merges on machine gates alone, no human approver. Design doc + flag req'd.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants