From 6fb26169cf6fec47d7333bb0a8dce69d85c1d678 Mon Sep 17 00:00:00 2001 From: "Zhongxuan (Daniel) Wang" Date: Tue, 28 Jul 2026 16:43:09 -0700 Subject: [PATCH 01/15] refactor: slim adapter runtime dependencies (#105) #### Overview Slim the Python adapter dependency boundary for the `release/0.1` line without changing adapter behavior. - `nemo-fabric` remains a metadata-only package that unconditionally installs the exact matching `nemo-fabric-runtime`. - Root harness extras delegate to the matching adapter package's `harness` extra. - Bare adapter distributions contain only adapter-owned runtime dependencies. - Every adapter provides `harness` and `full`; only Deep Agents and Hermes provide the Python `relay` extra. Claude and Codex continue to use the separately installed `nemo-relay` CLI. - Wrapped harness packages required by repository tests remain in the non-published `adapter-tests` dependency group. #### Details The supported install modes are now explicit: - `nemo-fabric[]`: Runtime, adapter, and supported harness dependencies in one environment. - `nemo-fabric` plus a bare adapter package: Runtime and adapter with an existing host-managed harness. - `nemo-fabric-adapters-[harness]`: Adapter and supported harness without Runtime, for a separate adapter interpreter. - Bare `nemo-fabric-adapters-`: Adapter-owned dependencies only. - Adapter `full`: All package-installable dependencies; for Claude and Codex this equals `harness` because Relay is an external CLI. The README, package description, install guide, adapter guides, Harbor examples, CI, consumer skill, and maintainer packaging skills now describe the same matrix. Metadata tests guard the root-to-adapter delegation and the exact adapter dependency boundaries. #### Validation - Focused metadata, README, and Harbor checks: `55 passed` - Full Python suite: `529 passed, 15 skipped` - Latest upstream Hermes streaming coverage plus metadata checks: `21 passed` - Root and all adapter lockfiles: `uv lock --check` - `just build-python` - `cargo check -p fabric-python --locked` - `just docs` (all checks passed; unauthenticated redirect check skipped with the expected warning) - `just wheels`, followed by root and adapter wheel `METADATA` inspection - License diff against `upstream/release/0.1`: no Rust or Python additions, removals, or changes - Full `pre-commit run --all-files` - `just --fmt --check` - `git diff --check` #### Where should the reviewer start? Start with `pyproject.toml`, the four adapter `pyproject.toml` files, and `tests/adapters/test_adapter_package_metadata.py`. Then review `docs/getting-started/install.mdx`, `.github/workflows/ci_python.yml`, and `.agents/skills/contribute-adapter/SKILL.md`. The branch is rebased onto the latest `release/0.1`. It includes and preserves the adapter configuration changes from #117. #### Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to) - Closes [FABRIC-125](https://linear.app/nvidia/issue/FABRIC-125/slim-adapter-runtime-dependencies) - Relates to #117 - [x] I confirm this contribution is my own work, or I have the right to submit it under this project's license. - [x] I searched existing issues and open pull requests, and this does not duplicate existing work. ## Summary by CodeRabbit * **Documentation** * Clarified installation options for runtime, adapters, harnesses, and Relay integrations. * Added supported Python version guidance and separate-environment setup instructions. * Updated Hermes, Claude, Codex, and Deep Agents quick starts and deployment scenarios. * Improved Harbor setup and command examples, including version-alignment guidance. * **Bug Fixes** * Improved Hermes configuration writing when YAML support is unavailable. * Clarified Relay CLI requirements and adapter-specific integration behavior. * **Tests** * Added validation for package dependency boundaries, installation metadata, and adapter configuration behavior. Authors: - Zhongxuan (Daniel) Wang (https://github.com/zhongxuanwang-nv) Approvers: - Anuradha Karuppiah (https://github.com/AnuradhaKaruppiah) - David Gardner (https://github.com/dagardner-nv) URL: https://github.com/NVIDIA/NeMo-Fabric/pull/105 --- .agents/skills/contribute-adapter/SKILL.md | 40 +- .agents/skills/maintain-packaging/SKILL.md | 7 + .agents/skills/python-tests/SKILL.md | 15 + .github/workflows/ci_python.yml | 7 +- CONTRIBUTING.md | 11 +- README.md | 75 +- adapters/claude/README.md | 37 +- adapters/claude/pyproject.toml | 9 +- adapters/claude/uv.lock | 43 +- adapters/codex/README.md | 32 +- adapters/codex/pyproject.toml | 9 +- adapters/codex/uv.lock | 19 +- adapters/deepagents/README.md | 35 +- adapters/deepagents/pyproject.toml | 19 +- .../deepagents/adapter.py | 11 +- adapters/deepagents/uv.lock | 72 +- adapters/hermes/README.md | 41 +- adapters/hermes/pyproject.toml | 13 +- adapters/hermes/uv.lock | 1265 ++++++++++++++++- docs/getting-started/install.mdx | 154 +- docs/getting-started/quickstart.mdx | 12 +- docs/integrations/harness/claude.mdx | 43 +- docs/integrations/harness/codex.mdx | 40 +- docs/integrations/harness/deepagents.mdx | 38 +- docs/integrations/harness/hermes.mdx | 41 +- docs/sdk/python.mdx | 2 +- examples/harbor/README.md | 24 +- examples/harbor/calculator/README.md | 10 +- .../calculator/task/environment/Dockerfile | 2 +- examples/harbor/swebench/README.md | 24 +- justfile | 4 +- pypi.md | 65 +- pyproject.toml | 29 +- .../consumer/nemo-fabric-integrate/SKILL.md | 30 +- .../adapters/test_adapter_package_metadata.py | 146 ++ tests/adapters/test_hermes_config_builder.py | 27 + tests/integrations/test_harbor_runner.py | 28 +- tests/python/test_harbor_integration.py | 4 +- tests/python/test_readme_examples.py | 2 +- uv.lock | 109 +- 40 files changed, 2264 insertions(+), 330 deletions(-) create mode 100644 tests/adapters/test_adapter_package_metadata.py diff --git a/.agents/skills/contribute-adapter/SKILL.md b/.agents/skills/contribute-adapter/SKILL.md index ad7b7786..43dd0c92 100644 --- a/.agents/skills/contribute-adapter/SKILL.md +++ b/.agents/skills/contribute-adapter/SKILL.md @@ -49,13 +49,38 @@ Decide the following before implementation: point, and focused tests. For Python, use `pyproject.toml`, `uv.lock`, `src/nemo_fabric_adapters//adapter.py`, and `tests/adapters/test_*.py`. Keep the package independent and small. -- Keep published runtime dependencies (`[project].dependencies` for Python) - razor-thin and adapter-owned. For an SDK/module boundary, declare every runtime - library the adapter host directly imports, including SDK/client libraries. For - an external process or separately managed harness environment, do not install - or upgrade the harness or consumer agent environment; keep test-only - dependencies in a non-published, language-native group - (`[dependency-groups]` for UV/Python). +- Keep each published leaf adapter's runtime dependencies + (`[project].dependencies` for Python) razor-thin and adapter-owned. Do not + declare the wrapped harness/SDK or dependencies directly declared by its + supported package. Do not treat incidental transitive dependencies as + harness-owned. Declare other libraries required by adapter behavior. When a + library is optional, provide and test the dependency-free fallback. A + separately managed harness means that the environment owner installs and + versions its SDK/module or provides its external executable or service; the + adapter must not install or upgrade it. +- Keep `nemo-fabric-runtime` as an exact-version unconditional dependency of the + root `nemo-fabric` metapackage. Give every installable Python harness adapter + one canonical root extra `` that depends on the matching version of + `nemo-fabric-adapters-[harness]`; the extra name does not need to + match the adapter directory. +- Keep a leaf adapter's base installation limited to adapter-owned dependencies. + Give every leaf a `harness` extra for its supported harness packages and a + `full` extra for every package-installable optional integration. If the + adapter imports NeMo Relay Python APIs, also provide a `relay` extra and + include it in `full`. If Relay is an external executable, do not provide a + leaf `relay` extra, and make `full` equivalent to `harness`. Document external + executable or service prerequisites separately. Do not add directory-name or + legacy aliases unless compatibility explicitly requires them. +- Install leaf adapters through their `harness` extras in the root + `adapter-tests` dependency group, and put other test-only packages in an + appropriate non-published group. For packaged harnesses, "compatible" means + satisfying the constraint declared by the leaf `harness` extra; document that + constraint for leaf-only installations. Derive exact pins or bounded ranges + from the supported upstream contract and test evidence; do not claim a + broader range than the evidence supports. Verify the unconditional root + runtime dependency, root-to-leaf harness delegation, `adapter-tests` + delegation, and leaf `harness`, `relay`, and `full` metadata. Inspect the + built root and leaf wheel metadata. - Start with the narrowest truthful `fabric-adapter.json`. Keep `config.accepts`, `config.generates`, requirements, telemetry declarations, and lifecycle capabilities synchronized with implementation and tests. @@ -151,6 +176,7 @@ and examples together when they expose the changed behavior. Run `validate-change` and the applicable adapter commands: ```bash +uv sync --group adapter-tests uv run --no-sync pytest tests/adapters/test_*.py just test-python just lock-python && just wheels # Package or dependency changes. diff --git a/.agents/skills/maintain-packaging/SKILL.md b/.agents/skills/maintain-packaging/SKILL.md index 6ba081fe..8c521def 100644 --- a/.agents/skills/maintain-packaging/SKILL.md +++ b/.agents/skills/maintain-packaging/SKILL.md @@ -34,6 +34,13 @@ consumed outside the source tree. Treat every direct dependency as a long-lived API, supply-chain, and licensing commitment. +- Keep `nemo-fabric` as a metapackage that unconditionally installs the + exact-version `nemo-fabric-runtime` distribution. Root harness extras delegate + to version-matched leaf adapter `harness` extras. Do not add root adapter-only + aliases. +- Keep leaf adapters adapter-only by default. Every leaf provides `harness` and + `full`; provide `relay` only when the adapter imports the NeMo Relay Python + package. For external Relay executables, `full` equals `harness`. - First prefer the standard library, an existing dependency, or a small local implementation when it keeps the behavior clear and maintainable. - When multiple dependencies satisfy the technical requirement, prefer the diff --git a/.agents/skills/python-tests/SKILL.md b/.agents/skills/python-tests/SKILL.md index e9e3ac62..0e27c711 100644 --- a/.agents/skills/python-tests/SKILL.md +++ b/.agents/skills/python-tests/SKILL.md @@ -36,6 +36,21 @@ license: Apache-2.0 ``` Simply allow the resulting KeyError to be raised if the "data" key is not present in the results dictionary, as this will provide a clear indication of what went wrong in the test. +## Packaging Metadata Tests + +When adapter installation metadata changes, assert the published composition +directly: + +- The root project unconditionally depends on the exact-version + `nemo-fabric-runtime` distribution. +- Each root harness extra delegates to the matching version of the leaf + adapter's `harness` extra. +- Bare leaf dependencies remain adapter-owned, and the root `adapter-tests` + dependency group installs each leaf through its `harness` extra. +- Every leaf provides `full`. Only adapters that import NeMo Relay Python APIs + provide `relay`; for adapters that use an external Relay executable, `full` + equals `harness`. + ## Common Commands ```bash diff --git a/.github/workflows/ci_python.yml b/.github/workflows/ci_python.yml index c7996959..24447056 100644 --- a/.github/workflows/ci_python.yml +++ b/.github/workflows/ci_python.yml @@ -83,12 +83,13 @@ jobs: with: shared-key: fabric-rust-${{ runner.os }}-${{ runner.arch }} - # PyYAML is not a project dependency, but test_hermes_config_mapping - # imports it to read Hermes Agent config fixtures, so install it for the tests. + # Exercise the supported root adapter and harness compositions. The + # adapter-tests group also keeps local test dependencies independently + # installable for leaf adapter development. - name: Build SDK with native extension run: | uv venv --python "${UV_PYTHON:-${{ matrix.python-version }}}" .venv - uv sync --group test --no-group dev --extra claude --extra codex --extra deepagents ${{ matrix.python-version != '3.11' && '--extra harbor' || '' }} ${{ matrix.python-version != '3.14' && '--extra hermes-agent' || '' }} --extra relay --extra runtime + uv sync --no-default-groups --group adapter-tests --group test --extra claude --extra codex --extra deepagents ${{ matrix.python-version != '3.11' && '--extra harbor' || '' }} ${{ matrix.python-version != '3.14' && '--extra hermes-agent' || '' }} --extra relay - name: Run pytest run: | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 46f5c211..4339fe95 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,16 +51,21 @@ The resulting wheel files are placed in the `dist/` directory. Install the packages into a virtual environment with: ```bash -uv pip install --find-links ./dist "nemo-fabric[runtime]" +uv pip install --find-links ./dist nemo-fabric ``` Adapters are distributed as optional extras. For example, install the Hermes -Agent adapter with: +Agent adapter and harness with: ```bash -uv pip install --find-links ./dist "nemo-fabric[hermes]" +uv pip install --find-links ./dist "nemo-fabric[hermes-agent]" ``` +To install only the Hermes adapter and its supported harness, use +`nemo-fabric-adapters-hermes[harness]`. Install +`nemo-fabric-adapters-hermes` without an extra when the environment already +manages a compatible Hermes Agent installation. + Refer to the [installation guide](docs/getting-started/install.mdx) for the complete list of adapters and installation options. diff --git a/README.md b/README.md index b57b3bda..ba0a0ba7 100644 --- a/README.md +++ b/README.md @@ -35,14 +35,21 @@ It provides: ## Supported Harnesses -NeMo Fabric provides the following harness integrations: - -| Agent Harness | Package Extra | -| --- | --- | -| [Claude Code](docs/integrations/harness/claude.mdx) | `nemo-fabric[claude]` | -| [Codex](docs/integrations/harness/codex.mdx) | `nemo-fabric[codex]` | -| [Hermes Agent](docs/integrations/harness/hermes.mdx) | `nemo-fabric[hermes]` | -| [LangChain Deep Agents](docs/integrations/harness/deepagents.mdx) | `nemo-fabric[deepagents]` | +NeMo Fabric provides the following harness integrations. The package +expressions install the components shown in each column: + +| Agent Harness | Runtime, Adapter, and Harness | Adapter and Harness | Adapter Only | +| --- | --- | --- | --- | +| [Claude Code](docs/integrations/harness/claude.mdx) | `nemo-fabric[claude]` | `nemo-fabric-adapters-claude[harness]` | `nemo-fabric-adapters-claude` | +| [Codex](docs/integrations/harness/codex.mdx) | `nemo-fabric[codex]` | `nemo-fabric-adapters-codex[harness]` | `nemo-fabric-adapters-codex` | +| [Hermes Agent](docs/integrations/harness/hermes.mdx) | `nemo-fabric[hermes-agent]` | `nemo-fabric-adapters-hermes[harness]` | `nemo-fabric-adapters-hermes` | +| [LangChain Deep Agents](docs/integrations/harness/deepagents.mdx) | `nemo-fabric[deepagents]` | `nemo-fabric-adapters-deepagents[harness]` | `nemo-fabric-adapters-deepagents` | + +The `nemo-fabric` package always installs the runtime, and each root harness +extra adds the corresponding adapter and supported harness. Use the +adapter-package forms for split environments or environments that already +manage the harness. For `harness`, `full`, and Relay behavior, refer to the +[installation guide](docs/getting-started/install.mdx). Capabilities vary by harness. Review the compatibility matrix and use plan() and doctor() before relying on optional capabilities such as MCP, skills, @@ -63,12 +70,14 @@ Agent in one Python environment. ### Install NeMo Fabric and Hermes Agent -Create and activate a virtual environment, then install the required packages: +Hermes Agent supports Python 3.11 through 3.13. With a supported Python +version, create and activate a virtual environment, then install the required +packages: ```bash python -m venv .venv source .venv/bin/activate -pip install "nemo-fabric[runtime, hermes-agent]" +pip install "nemo-fabric[hermes-agent]" ``` ### Set the API Key @@ -123,25 +132,42 @@ For a guided version of this example, refer to the [example notebooks overview](examples/notebooks/README.md) describes the other available notebooks. -## Use Separate Environments +## Deployment Scenarios + +### Scenario 1: Runtime and Harness in the Same Environment + +This is the simplest deployment. The `nemo-fabric` package, selected adapter, +and supported harness share one Python environment. The quick start above uses +this model with `nemo-fabric[hermes-agent]`. -The quick start uses one Python environment. Real-world deployments commonly -separate the application or evaluation host from the task environment where -NeMo Fabric and the selected harness run. For example, Harbor constructs -`FabricConfig` in its host process, then runs NeMo Fabric, the adapter, and the -harness inside an isolated task container. Refer to the +### Scenario 2: Isolated Sandbox for Task Execution + +This is the Harbor deployment model. The Harbor host constructs and serializes +the final typed `FabricConfig`. Harbor then installs and runs NeMo Fabric, the +selected adapter, and the harness inside an isolated task environment such as a +Docker container or Daytona sandbox. Adapter discovery and task-path resolution +occur inside that sandbox. + +Install `nemo-fabric[harbor]==0.1.0` in the host environment. Install a complete +harness composition such as `nemo-fabric[claude]==0.1.0` or +`nemo-fabric[hermes-agent,relay]==0.1.0` in the task environment. For Claude or +Codex Relay streaming, also provision the external NeMo Relay CLI in the task +environment. Refer to the [Harbor execution model](examples/harbor/README.md#execution-model) for details. -NeMo Fabric can also operate with the NeMo Fabric runtime and the agent harness -in separate Python environments. This setup can match existing deployment -boundaries and isolate their dependencies. +### Scenario 3: Runtime and Harness in Separate Python Environments + +NeMo Fabric can run the runtime and agent harness in separate, locally +accessible Python environments. This setup isolates their Python dependencies +while the runtime launches the adapter through the adapter environment's +interpreter. Create an environment for the NeMo Fabric runtime: ```bash python -m venv .venv-fabric source .venv-fabric/bin/activate -pip install "nemo-fabric[runtime]" +pip install nemo-fabric==0.1.0 ``` Create another environment for the adapter and harness. For example, install @@ -150,11 +176,14 @@ the Hermes Agent integration: ```bash python -m venv .venv-hermes source .venv-hermes/bin/activate -pip install "nemo-fabric[hermes-agent]" +pip install "nemo-fabric-adapters-hermes[harness]==0.1.0" ``` -**Note:** The `nemo-fabric[hermes-agent]` package extra installs the Hermes Agent adapter and Hermes Agent itself, to install just the adapter, use `nemo-fabric[hermes]`. - +The adapter package keeps this environment independent from the +`nemo-fabric` distribution. Its `harness` extra installs the compatible Hermes +Agent dependency alongside the adapter. Use matching NeMo Fabric release +versions for the runtime and adapter package unless a different pairing has +been explicitly validated. Run NeMo Fabric from its environment and set `ADAPTER_PYTHON` to the interpreter that contains the adapter and harness: diff --git a/adapters/claude/README.md b/adapters/claude/README.md index f7950528..f13ad2f0 100644 --- a/adapters/claude/README.md +++ b/adapters/claude/README.md @@ -9,22 +9,26 @@ The `nvidia.fabric.claude` adapter uses the official Claude Agent SDK for Python behind NeMo Fabric's normalized invocation contract. The SDK is an implementation detail; consumers select the Claude harness by adapter ID. -This adapter pins `claude-agent-sdk==0.2.120`. The SDK supplies and selects its -compatible Claude Code runtime. +The `harness` extra pins `claude-agent-sdk==0.2.120`; use the same version for an +environment-managed SDK. The SDK supplies a compatible Claude Code runtime. ## Install -To install just the Claude adapter by itself: +The following table shows which components each installation provides: -```bash -pip install "nemo-fabric[claude]" -``` +| Installation | Runtime | Adapter | Harness | NeMo Relay CLI | +| --- | --- | --- | --- | --- | +| `pip install "nemo-fabric[claude]"` | Yes | Yes | Yes | No | +| `pip install "nemo-fabric-adapters-claude[harness]"` | No | Yes | Yes | No | +| `pip install nemo-fabric-adapters-claude` | No | Yes | No | No | -To install just the Claude adapter along with the NeMo Fabric Runtime: +For split runtime and adapter environments, configure `ADAPTER_PYTHON` or +`harness.settings.python` and use matching NeMo Fabric release versions. Refer +to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-an-adapter-and-harness-without-the-runtime). -```bash -pip install "nemo-fabric[claude, runtime]" -``` +The `full` extra is equivalent to `harness`. Relay is optional for ordinary +runs. Relay telemetry and `Runtime.invoke_stream()` require the external CLI +described under [Relay Observability](#relay-observability). ## Authentication @@ -58,12 +62,6 @@ Refer to the [Claude adapter authentication guide](https://nvidia-nemo-fabric.do for mode selection, required WIF variables, and the Relay boundary. Package installation is verified by the adapter wheel and module-entrypoint tests. -Relay-enabled runs also require the external `nemo-relay` CLI. Refer to the [NeMo Relay CLI](https://docs.nvidia.com/nemo/fabric/getting-started/install#nemo-relay-cli) install guide for instructions on installing the CLI tool. - -The Python `nemo-relay` package does not install this executable. Refer to the -[NeMo Relay installation guide](https://docs.nvidia.com/nemo/relay/getting-started/installation) -for other supported installation methods. - ## Execution Model The Claude adapter implements NeMo Fabric's persistent local-host wire protocol. @@ -113,6 +111,10 @@ by the SDK and is not persisted as a NeMo Fabric artifact. ## Relay Observability +Relay requires a separately installed NeMo Relay 0.6.x CLI on `PATH`; the Python +`nemo-relay` package does not provide the executable. Follow the +[NeMo Relay installation instructions](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-nemo-relay). + Enable Relay through the normalized NeMo Fabric configuration: ```python @@ -134,8 +136,7 @@ gateway has the same lifecycle as that single invocation. The NeMo Fabric result includes `relay_runtime.gateway_config_path`, `relay_runtime.gateway_log_path`, and the collected `relay_artifacts`. Relay startup failures return a stable adapter error and retain the gateway log for -diagnosis. The default Claude Agent SDK dependency bundles a compatible Claude -Code executable. +diagnosis. ## Typed Configuration diff --git a/adapters/claude/pyproject.toml b/adapters/claude/pyproject.toml index f80d8098..86874789 100644 --- a/adapters/claude/pyproject.toml +++ b/adapters/claude/pyproject.toml @@ -26,10 +26,17 @@ readme = "README.md" requires-python = ">=3.11" dependencies = [ "nemo-fabric-adapters-common == 0.1.0", - "claude-agent-sdk==0.2.120", "tomli-w~=1.2", ] +[project.optional-dependencies] +harness = [ + "claude-agent-sdk==0.2.120", +] +full = [ + "claude-agent-sdk==0.2.120", +] + [project.urls] Repository = "https://github.com/NVIDIA/nemo-fabric/" Documentation = "https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric" diff --git a/adapters/claude/uv.lock b/adapters/claude/uv.lock index 012c18e1..7f75a332 100644 --- a/adapters/claude/uv.lock +++ b/adapters/claude/uv.lock @@ -10,24 +10,24 @@ resolution-markers = [ [[package]] name = "annotated-types" -version = "0.7.0" +version = "0.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/56/a8120250d128bed162cd73c76d45f6ef9991f3e068f62a8ee060afa3104a/annotated_types-0.8.0.tar.gz", hash = "sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7", size = 15893, upload-time = "2026-07-23T20:16:13.995Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, + { url = "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl", hash = "sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0", size = 13427, upload-time = "2026-07-23T20:16:12.938Z" }, ] [[package]] name = "anyio" -version = "4.14.1" +version = "4.14.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3b/72/5562aabb8dd7181e8e860622a38bea08d17842b99ecd4c91f84ac95251b0/anyio-4.14.1.tar.gz", hash = "sha256:8d648a3544c1a700e3ff78615cd679e4c5c3f149904287e73687b2596963629e", size = 254831, upload-time = "2026-06-24T20:56:06.017Z" } +sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl", hash = "sha256:4e5533c5b8ff0a24f5d7a176cbe6877129cd183893f66b537f8f227d10527d72", size = 124875, upload-time = "2026-06-24T20:56:04.413Z" }, + { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" }, ] [[package]] @@ -41,11 +41,11 @@ wheels = [ [[package]] name = "certifi" -version = "2026.6.17" +version = "2026.7.22" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432", size = 134594, upload-time = "2026-06-17T10:31:07.894Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db", size = 133289, upload-time = "2026-06-17T10:31:06.348Z" }, + { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" }, ] [[package]] @@ -325,7 +325,7 @@ wheels = [ [[package]] name = "mcp" -version = "1.28.1" +version = "1.29.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -343,9 +343,9 @@ dependencies = [ { name = "typing-inspection" }, { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6e/77/9450b8f251a13affb6281997d0523c4615f8a8b35d0b21ff30db3a5aac9d/mcp-1.28.1.tar.gz", hash = "sha256:d51e36a5f5644faea4f85ea649bfffa6bc6c26770d42798ad6a3de3d2ba69683", size = 638501, upload-time = "2026-06-26T12:57:29.093Z" } +sdist = { url = "https://files.pythonhosted.org/packages/30/d3/f9acc21dfc886e4f78e2add1a47db46ce16884346afde53f8a064c02c891/mcp-1.29.0.tar.gz", hash = "sha256:52d01f334de1868cc3bb2d6604931126a67631f99a6c5d3b82ba47290315ec36", size = 643148, upload-time = "2026-07-28T13:41:41.939Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/5e/d118fce19f87a2e7d8101c35c8ae0ec289098a4df0ff244cec23e415aca0/mcp-1.28.1-py3-none-any.whl", hash = "sha256:2726bca5e7193f61c5dde8b12500a6de2d9acf6d1a1c0be9e8c2e706437991df", size = 222620, upload-time = "2026-06-26T12:57:27.218Z" }, + { url = "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl", hash = "sha256:f5a075bb611f23d6f4d080c6a1699fa62772eebc562ba9e66b306ddde1c755f7", size = 223436, upload-time = "2026-07-28T13:41:40.337Z" }, ] [[package]] @@ -353,17 +353,26 @@ name = "nemo-fabric-adapters-claude" version = "0.1.0" source = { editable = "." } dependencies = [ - { name = "claude-agent-sdk" }, { name = "nemo-fabric-adapters-common" }, { name = "tomli-w" }, ] +[package.optional-dependencies] +full = [ + { name = "claude-agent-sdk" }, +] +harness = [ + { name = "claude-agent-sdk" }, +] + [package.metadata] requires-dist = [ - { name = "claude-agent-sdk", specifier = "==0.2.120" }, + { name = "claude-agent-sdk", marker = "extra == 'full'", specifier = "==0.2.120" }, + { name = "claude-agent-sdk", marker = "extra == 'harness'", specifier = "==0.2.120" }, { name = "nemo-fabric-adapters-common", editable = "../common" }, { name = "tomli-w", specifier = "~=1.2" }, ] +provides-extras = ["harness", "full"] [[package]] name = "nemo-fabric-adapters-common" @@ -712,15 +721,15 @@ wheels = [ [[package]] name = "sse-starlette" -version = "3.4.5" +version = "3.4.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "starlette" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d2/1b/bc9e3e7a72dcdad7dc7888758f5d00f56f8909ed5cfdff822bd72bb4c520/sse_starlette-3.4.5.tar.gz", hash = "sha256:83072538bc211a2f68b7b0422226c4af3e9b62e106e07034664b832ca019842a", size = 35249, upload-time = "2026-06-20T17:36:58.322Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/10/a34c656829ffc1c4b22ef36d70d9ebb6b99c020e2aeb17cee5485099f028/sse_starlette-3.4.6.tar.gz", hash = "sha256:725f8a1bd6d26ae1b2c9610c0ef5065dfdd496f3988d28adcf8c4b49dc25c627", size = 32542, upload-time = "2026-07-20T14:16:32.201Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/75/c88d3f5dafd59c791da1ce27650d30bf5b70cbf1cbf01cd00e5f9e360915/sse_starlette-3.4.5-py3-none-any.whl", hash = "sha256:e71bad53323f65573c3864a6c3bd0c1eb6e5f092b2e48082b0c35927d19ca296", size = 16518, upload-time = "2026-06-20T17:36:56.729Z" }, + { url = "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl", hash = "sha256:56217ab4c9a9f9c5db7b21e08732d3e7c2b807f45231ad23de0551a24c4a41f6", size = 16516, upload-time = "2026-07-20T14:16:30.978Z" }, ] [[package]] diff --git a/adapters/codex/README.md b/adapters/codex/README.md index b14b5e33..7d81a83d 100644 --- a/adapters/codex/README.md +++ b/adapters/codex/README.md @@ -12,17 +12,22 @@ app-server runtime and typed JSON-RPC protocol. ## Install -To install just the Codex adapter by itself: +The following table shows which components each installation provides: -```bash -pip install "nemo-fabric[codex]" -``` +| Installation | Runtime | Adapter | Harness | NeMo Relay CLI | +| --- | --- | --- | --- | --- | +| `pip install "nemo-fabric[codex]"` | Yes | Yes | Yes | No | +| `pip install "nemo-fabric-adapters-codex[harness]"` | No | Yes | Yes | No | +| `pip install nemo-fabric-adapters-codex` | No | Yes | No | No | -To install just the Codex adapter along with the NeMo Fabric Runtime: +For an environment-managed SDK, use `openai-codex==0.144.4`. For split runtime +and adapter environments, configure `ADAPTER_PYTHON` or +`harness.settings.python` and use matching NeMo Fabric release versions. Refer +to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-an-adapter-and-harness-without-the-runtime). -```bash -pip install "nemo-fabric[codex, runtime]" -``` +The `full` extra is equivalent to `harness`. Relay is optional for ordinary +runs. Relay telemetry and `Runtime.invoke_stream()` require the external CLI +described under [Relay Integration](#relay-integration). ## Authentication @@ -58,7 +63,7 @@ NeMo Fabric artifact root, so execution does not depend on or modify a user's Codex login. Provider names identify configuration; the adapter does not maintain a provider allowlist. -The adapter depends on the Codex SDK, which installs and selects its matching +The adapter uses the Codex SDK, which installs and selects its matching app-server runtime. NeMo Fabric does not declare the runtime package directly or treat it as a user-installed command or adapter descriptor requirement. @@ -130,7 +135,12 @@ Codex state variables, the selected model's `api_key_env`, and explicit ## Relay Integration -Relay-enabled runs also require the external `nemo-relay` CLI. Refer to the -[NeMo Relay CLI](https://docs.nvidia.com/nemo/fabric/getting-started/install#nemo-relay-cli) install guide for instructions on installing the CLI tool. +Relay requires a separately installed NeMo Relay 0.6.x CLI on `PATH`; the Python +`nemo-relay` package does not provide the executable. Follow the +[NeMo Relay installation instructions](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-nemo-relay). + +Enable Relay with `FabricConfig.enable_relay(...)`. The adapter starts the +installed `nemo-relay` CLI as a supervised sidecar; do not start the gateway +separately. NeMo Fabric routes the selected Responses-compatible provider through the gateway and passes its explicit `base_url` to Relay as the upstream endpoint. diff --git a/adapters/codex/pyproject.toml b/adapters/codex/pyproject.toml index 7acd61c0..bbdbc08f 100644 --- a/adapters/codex/pyproject.toml +++ b/adapters/codex/pyproject.toml @@ -26,10 +26,17 @@ readme = "README.md" requires-python = ">=3.11" dependencies = [ "nemo-fabric-adapters-common == 0.1.0", - "openai-codex==0.144.4", "tomli-w~=1.2", ] +[project.optional-dependencies] +harness = [ + "openai-codex==0.144.4", +] +full = [ + "openai-codex==0.144.4", +] + [project.urls] Repository = "https://github.com/NVIDIA/nemo-fabric/" Documentation = "https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric" diff --git a/adapters/codex/uv.lock b/adapters/codex/uv.lock index a76f126a..2fb0e3db 100644 --- a/adapters/codex/uv.lock +++ b/adapters/codex/uv.lock @@ -4,11 +4,11 @@ requires-python = ">=3.11" [[package]] name = "annotated-types" -version = "0.7.0" +version = "0.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/56/a8120250d128bed162cd73c76d45f6ef9991f3e068f62a8ee060afa3104a/annotated_types-0.8.0.tar.gz", hash = "sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7", size = 15893, upload-time = "2026-07-23T20:16:13.995Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, + { url = "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl", hash = "sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0", size = 13427, upload-time = "2026-07-23T20:16:12.938Z" }, ] [[package]] @@ -17,16 +17,25 @@ version = "0.1.0" source = { editable = "." } dependencies = [ { name = "nemo-fabric-adapters-common" }, - { name = "openai-codex" }, { name = "tomli-w" }, ] +[package.optional-dependencies] +full = [ + { name = "openai-codex" }, +] +harness = [ + { name = "openai-codex" }, +] + [package.metadata] requires-dist = [ { name = "nemo-fabric-adapters-common", editable = "../common" }, - { name = "openai-codex", specifier = "==0.144.4" }, + { name = "openai-codex", marker = "extra == 'full'", specifier = "==0.144.4" }, + { name = "openai-codex", marker = "extra == 'harness'", specifier = "==0.144.4" }, { name = "tomli-w", specifier = "~=1.2" }, ] +provides-extras = ["harness", "full"] [[package]] name = "nemo-fabric-adapters-common" diff --git a/adapters/deepagents/README.md b/adapters/deepagents/README.md index 5985a530..828c6fcd 100644 --- a/adapters/deepagents/README.md +++ b/adapters/deepagents/README.md @@ -9,17 +9,24 @@ Runs a [LangChain Deep Agents](https://github.com/langchain-ai/deepagents) agent inside NeMo Fabric's persistent Python adapter host. One started runtime retains the compiled graph, checkpointer, and LangGraph thread across ordered invocations. -To install just the Deep Agents adapter by itself: +## Install -```bash -pip install "nemo-fabric[deepagents]" -``` +The following table shows which components each installation provides: -To install just the Deep Agents adapter along with the NeMo Fabric Runtime: +| Installation | Runtime | Adapter | Harness | NeMo Relay Python Package | +| --- | --- | --- | --- | --- | +| `pip install "nemo-fabric[deepagents]"` | Yes | Yes | Yes | No | +| `pip install "nemo-fabric[deepagents,relay]"` | Yes | Yes | Yes | Yes | +| `pip install "nemo-fabric-adapters-deepagents[harness]"` | No | Yes | Yes | No | +| `pip install "nemo-fabric-adapters-deepagents[full]"` | No | Yes | Yes | Yes | +| `pip install "nemo-fabric-adapters-deepagents[relay]"` | No | Yes | No | Yes | +| `pip install nemo-fabric-adapters-deepagents` | No | Yes | No | No | -```bash -pip install "nemo-fabric[deepagents, runtime]" -``` +For an environment-managed stack, use `deepagents>=0.6.12,<0.7.0`, +`langchain>=1.3,<2.0`, and `langgraph>=1.2,<2.0`. For split runtime and adapter +environments, configure `ADAPTER_PYTHON` or `harness.settings.python` and use +matching NeMo Fabric release versions. Refer to the +[installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-an-adapter-and-harness-without-the-runtime). ## Model and Authentication @@ -39,8 +46,7 @@ configuration failure), so a key is never sent to the wrong endpoint. Because `models..api_key_env` is provider-specific, the adapter declares no static env requirement; a runtime **preflight** verifies that the `deepagents` package is importable and the configured credential is set. A failed preflight -fails runtime start with a stable lifecycle error. `fabric doctor` validates -adapter resolution. +fails runtime start with a stable lifecycle error. NeMo Fabric maps the following into the harness: @@ -134,12 +140,9 @@ async with await client.start_runtime(config, base_dir=BASE_DIR) as runtime: NeMo Relay is Deep Agents' single, SDK-native observability path — the adapter does not expose gateway, CLI, or plugin launch modes for this harness. Relay is **optional**: `nemo_relay` is imported lazily and only when telemetry is enabled, -so the core install stays Relay-neutral at import time. Install it through Relay's -own `deepagents` integration extra: - -```bash -pip install "nemo-fabric-adapters-deepagents[relay]" # -> nemo-relay[deepagents] -``` +so the core install stays Relay-neutral at import time. Relay telemetry and +`Runtime.invoke_stream()` require one of the installations in the table that +includes the NeMo Relay Python package. - **Relay** (`telemetry.providers.relay`): the SDK-native integration attaches three complementary pieces around `create_deep_agent`, applied uniformly to diff --git a/adapters/deepagents/pyproject.toml b/adapters/deepagents/pyproject.toml index ceb261b0..ed447d28 100644 --- a/adapters/deepagents/pyproject.toml +++ b/adapters/deepagents/pyproject.toml @@ -26,23 +26,26 @@ readme = "README.md" requires-python = ">=3.11" dependencies = [ "nemo-fabric-adapters-common == 0.1.0", - "deepagents>=0.6.12,<0.7.0", - "langchain>=1.3,<2.0", "langchain-mcp-adapters>=0.1,<0.3.0", "langchain-openai>=0.3", - "langgraph>=1.2,<2.0", # Requires 3.x: the 2.x line is incompatible with the langgraph core deepagents # pulls (AsyncSqliteSaver fails with 'Connection has no attribute is_alive'). "langgraph-checkpoint-sqlite>=3.0,<4.0", ] -# NeMo Relay is an optional, SDK-native integration. It is installed through -# Relay's own ``deepagents`` extra, which pulls the Deep Agents / LangGraph -# instrumentation Relay needs. The adapter imports nemo_relay lazily and only -# when telemetry.providers.relay is enabled, so the core install stays -# Relay-neutral at import time. [project.optional-dependencies] +harness = [ + "deepagents>=0.6.12,<0.7.0", + "langchain>=1.3,<2.0", + "langgraph>=1.2,<2.0", +] relay = [ + "nemo-relay>=0.6.0,<0.7", +] +full = [ + "deepagents>=0.6.12,<0.7.0", + "langchain>=1.3,<2.0", + "langgraph>=1.2,<2.0", "nemo-relay[deepagents]>=0.6.0,<0.7", ] diff --git a/adapters/deepagents/src/nemo_fabric_adapters/deepagents/adapter.py b/adapters/deepagents/src/nemo_fabric_adapters/deepagents/adapter.py index a0546644..0330bee8 100644 --- a/adapters/deepagents/src/nemo_fabric_adapters/deepagents/adapter.py +++ b/adapters/deepagents/src/nemo_fabric_adapters/deepagents/adapter.py @@ -118,10 +118,11 @@ def main() -> None: def preflight_check(payload: dict[str, Any]) -> None: """Validate invocation-time prerequisites and fail fast with clear errors. - These are runtime preflight checks, not ``fabric doctor`` checks: Fabric core - has no adapter-doctor hook, so doctor cannot verify these. At invocation time - the ``deepagents`` package must be importable and the configured - model-provider credential must be present in the environment. + These checks run during adapter startup. Core descriptor diagnostics do not + invoke adapter-specific preflight hooks, so they cannot verify these + prerequisites. At invocation time the ``deepagents`` package must be + importable and the configured model-provider credential must be present in + the environment. """ import importlib.util @@ -129,7 +130,7 @@ def preflight_check(payload: dict[str, Any]) -> None: if importlib.util.find_spec("deepagents") is None: raise RuntimeError( "the 'deepagents' package is required for the Deep Agents adapter; install " - "it with the 'deepagents' extra (pip install nemo-fabric-adapters-deepagents)." + "a compatible Deep Agents harness in the adapter environment." ) model_config = selected_model_config(payload) diff --git a/adapters/deepagents/uv.lock b/adapters/deepagents/uv.lock index 72d964e8..d7cadbe6 100644 --- a/adapters/deepagents/uv.lock +++ b/adapters/deepagents/uv.lock @@ -28,7 +28,7 @@ wheels = [ [[package]] name = "anthropic" -version = "0.116.0" +version = "0.120.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -40,9 +40,9 @@ dependencies = [ { name = "sniffio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/a2/d31f14e28d49bae983a3634e38dfb4b31c50110b5e403596c5c6a20b23f8/anthropic-0.116.0.tar.gz", hash = "sha256:5fc248fbb9fe03ef686f8a774f81586bca31a043260aab88b387ea3660f4a396", size = 949149, upload-time = "2026-07-02T19:08:10.534Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/10/4ca013cb166f226bd89e0aeb0fcaff94f45ddf716d4925ce89475d3c587b/anthropic-0.120.2.tar.gz", hash = "sha256:9722efc10c27a30a69f5338ddacdb35bc6a64297a4e4ba729bf83af873d5fb3a", size = 1008421, upload-time = "2026-07-28T17:38:26.986Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/dd/2a1e81cf1b163acc340afc4ec74ed1d86f5eed1a809fabdeed3e0997b346/anthropic-0.116.0-py3-none-any.whl", hash = "sha256:6c0a7698e8d652455da3499978279bb2588c7264d0a35be3666009a4258c8256", size = 956896, upload-time = "2026-07-02T19:08:08.756Z" }, + { url = "https://files.pythonhosted.org/packages/63/af/0f5db57b9397a0f3b7fc204cbef143401a7cadaf982330f97f1ce3d39f34/anthropic-0.120.2-py3-none-any.whl", hash = "sha256:0f0bc2b381dc0eb41c8d886b815d79c2041cd2374f83aed36f574b6dc9c579c1", size = 1022851, upload-time = "2026-07-28T17:38:25.466Z" }, ] [[package]] @@ -69,11 +69,11 @@ wheels = [ [[package]] name = "bracex" -version = "3.0" +version = "3.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/f5/4473ad9b48cd0420a2d762a3750fa0e078e23e060b1af72662e5987e5530/bracex-3.0.tar.gz", hash = "sha256:b73f718d6bd98d8419e45df02426c86e9967c179949f779340d6c3a8c83b9111", size = 43162, upload-time = "2026-06-30T00:43:35.279Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ac/01/5f394b8bcd6e5b92f73130990960423bbb19711f906bd9fe9ea5557c667c/bracex-3.0.1.tar.gz", hash = "sha256:4e38e32392e4a4780fe15d644bfc7c8514057cfc3861e060b11814ce829c25e4", size = 44019, upload-time = "2026-07-20T13:43:00.335Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f5/2e/68781b78e764e5ccc4af1e3d27e060069c73af90234853fa80000e7ee79d/bracex-3.0-py3-none-any.whl", hash = "sha256:3833e61c2f092d5aa0468fa2e6c6e990a306185abf763b6d122f0158e59c58a5", size = 11738, upload-time = "2026-06-30T00:43:34.196Z" }, + { url = "https://files.pythonhosted.org/packages/b8/8f/6f7273a7adb8d73fc8d21ede4376a3e475e52f98435c6007f69100dec8ca/bracex-3.0.1-py3-none-any.whl", hash = "sha256:6523ad83aeb5098a4ee597cff0f964442ff74e460bd3fafaffab6a013ff2288c", size = 11940, upload-time = "2026-07-20T13:42:59.268Z" }, ] [[package]] @@ -380,15 +380,15 @@ wheels = [ [[package]] name = "google-auth" -version = "2.55.2" +version = "2.56.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, { name = "pyasn1-modules" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/79/b9/e370d86fea3da13ec0256df30323dd26c0cb9c8c85f0c6ec42ac9df0106b/google_auth-2.55.2.tar.gz", hash = "sha256:97ae7790ff740f2bc9db60eb864a7804f4ac19f5f02c38b3d942f2fea6e9b9ae", size = 361414, upload-time = "2026-07-07T18:43:21.227Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/33/dbc946a407401b975f0719658f18e664ece2109f79ffd1ff3bf226c205f4/google_auth-2.56.2.tar.gz", hash = "sha256:e28f103ca8091fb7012b99c44243d7366c29863713b8e34a220c3322b7a07051", size = 365820, upload-time = "2026-07-21T21:53:28.188Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/c6/02eb5a337ac316a4c30c012e747bad5cea36e1a876efecdf80865541f7d8/google_auth-2.55.2-py3-none-any.whl", hash = "sha256:d715f265f2cafc6a5f1bf0dc19870d20e3119f6f6682785a250bce3d03d38a3b", size = 256778, upload-time = "2026-07-07T18:43:19.52Z" }, + { url = "https://files.pythonhosted.org/packages/88/63/50636aae68c9bf17c891c7eb18b49baa9bd6b31d2a97b8de4813a9fc8d1c/google_auth-2.56.2-py3-none-any.whl", hash = "sha256:c8270ea95b2697b74e3d8438ae9c5b898e38b623b915c7b5c5635921e7de68a6", size = 258588, upload-time = "2026-07-21T21:53:26.399Z" }, ] [package.optional-dependencies] @@ -398,7 +398,7 @@ requests = [ [[package]] name = "google-genai" -version = "2.10.0" +version = "2.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -412,9 +412,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cd/fe/b796087493c3c55371aa58b9f264841ace5bfdf8c668cafa7afa33c44bec/google_genai-2.10.0.tar.gz", hash = "sha256:77912cd558cd7dfd5b75c25fd1c609e78d7954dde583331104022a46ea90f9ee", size = 600039, upload-time = "2026-06-24T01:33:18.157Z" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/df/4f820054c99f29f2fe3de4a8a7c9534dd795302e4a07483a0cb07c3a29b6/google_genai-2.14.0.tar.gz", hash = "sha256:a9d1f4f362d76280f1be1340fcb3c86e63dbca128f6a4ae09d86ab47ff7148e8", size = 641055, upload-time = "2026-07-22T21:35:44.717Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/39/00bcfd94de255d24249401efff4f48d77bf6066b46447e519fa193c0c299/google_genai-2.10.0-py3-none-any.whl", hash = "sha256:d5350311567ae660c24cbc1752aee4b3d660f89c0106d2dcd2a69978c35afe1e", size = 957974, upload-time = "2026-06-24T01:33:16.296Z" }, + { url = "https://files.pythonhosted.org/packages/ba/86/5ac5fb53e44cca4a6607fb917eb331fa237c65a103b9ec2e8e8acc8a42db/google_genai-2.14.0-py3-none-any.whl", hash = "sha256:ae7172cdd35695189b516b33a878e4132e5daa2dbc03a5b44cddfa8a82fad664", size = 1030738, upload-time = "2026-07-22T21:35:42.785Z" }, ] [[package]] @@ -711,7 +711,7 @@ wheels = [ [[package]] name = "langgraph" -version = "1.2.9" +version = "1.2.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "langchain-core" }, @@ -721,9 +721,9 @@ dependencies = [ { name = "pydantic" }, { name = "xxhash" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/41/4b/0d1130e26b41a99dcc88353bbe7162a1f255c4db746bd94024268e6af27b/langgraph-1.2.9.tar.gz", hash = "sha256:385f87bc1802c35af7e0aa479278ecba8582d103515eb48256cb2ddcd42d0bd4", size = 722869, upload-time = "2026-07-10T01:30:14.985Z" } +sdist = { url = "https://files.pythonhosted.org/packages/70/1d/a32f3caf4b3d60651656c0d64976b48d168653e81c71bb7512e9a31541aa/langgraph-1.2.10.tar.gz", hash = "sha256:05a183a746ed570a06c7c1b879920163509a75df9e44e92dd2238218d677fd37", size = 723404, upload-time = "2026-07-28T18:33:51.441Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/16/0b8dc48823f1326f3e0c8012a3c07a40da6f194299e2ec080df236287baf/langgraph-1.2.9-py3-none-any.whl", hash = "sha256:c2d98ad94333937922ba04148641c1da2bfe45b5b8e55d7b6dcb0bb2df809e76", size = 247473, upload-time = "2026-07-10T01:30:13.733Z" }, + { url = "https://files.pythonhosted.org/packages/e2/4d/3fc3e2535ee2c731130d71371848ebc6d4a9d2e8ae6060b11987ba134951/langgraph-1.2.10-py3-none-any.whl", hash = "sha256:52c48bd42fa31a1de0e1c0f0ebfe342e11ca2957b8b3563f83dbd60d8e30f921", size = 247753, upload-time = "2026-07-28T18:33:50.028Z" }, ] [[package]] @@ -842,32 +842,44 @@ name = "nemo-fabric-adapters-deepagents" version = "0.1.0" source = { editable = "." } dependencies = [ - { name = "deepagents" }, - { name = "langchain" }, { name = "langchain-mcp-adapters" }, { name = "langchain-openai" }, - { name = "langgraph" }, { name = "langgraph-checkpoint-sqlite" }, { name = "nemo-fabric-adapters-common" }, ] [package.optional-dependencies] -relay = [ +full = [ + { name = "deepagents" }, + { name = "langchain" }, + { name = "langgraph" }, { name = "nemo-relay", extra = ["deepagents"] }, ] +harness = [ + { name = "deepagents" }, + { name = "langchain" }, + { name = "langgraph" }, +] +relay = [ + { name = "nemo-relay" }, +] [package.metadata] requires-dist = [ - { name = "deepagents", specifier = ">=0.6.12,<0.7.0" }, - { name = "langchain", specifier = ">=1.3,<2.0" }, + { name = "deepagents", marker = "extra == 'full'", specifier = ">=0.6.12,<0.7.0" }, + { name = "deepagents", marker = "extra == 'harness'", specifier = ">=0.6.12,<0.7.0" }, + { name = "langchain", marker = "extra == 'full'", specifier = ">=1.3,<2.0" }, + { name = "langchain", marker = "extra == 'harness'", specifier = ">=1.3,<2.0" }, { name = "langchain-mcp-adapters", specifier = ">=0.1,<0.3.0" }, { name = "langchain-openai", specifier = ">=0.3" }, - { name = "langgraph", specifier = ">=1.2,<2.0" }, + { name = "langgraph", marker = "extra == 'full'", specifier = ">=1.2,<2.0" }, + { name = "langgraph", marker = "extra == 'harness'", specifier = ">=1.2,<2.0" }, { name = "langgraph-checkpoint-sqlite", specifier = ">=3.0,<4.0" }, { name = "nemo-fabric-adapters-common", editable = "../common" }, - { name = "nemo-relay", extras = ["deepagents"], marker = "extra == 'relay'", specifier = ">=0.6.0,<0.7" }, + { name = "nemo-relay", marker = "extra == 'relay'", specifier = ">=0.6.0,<0.7" }, + { name = "nemo-relay", extras = ["deepagents"], marker = "extra == 'full'", specifier = ">=0.6.0,<0.7" }, ] -provides-extras = ["relay"] +provides-extras = ["harness", "relay", "full"] [[package]] name = "nemo-relay" @@ -1038,11 +1050,11 @@ wheels = [ [[package]] name = "pyasn1" -version = "0.6.3" +version = "0.6.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a4/9a/23310166d960def5897e91fe20e5b724601b02a22e84ba1f94232c0b7f67/pyasn1-0.6.4.tar.gz", hash = "sha256:9c447d8431c947fe4c8febc4ed9e760bc29011a5b01e5c74b67025bd9fb8ce81", size = 151262, upload-time = "2026-07-09T01:12:33.988Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" }, + { url = "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl", hash = "sha256:deda9277cfd454080ec40b207fb6df82206a3a2688735233cdcd8d3d565f088b", size = 84410, upload-time = "2026-07-09T01:12:32.92Z" }, ] [[package]] @@ -1828,14 +1840,14 @@ wheels = [ [[package]] name = "wcmatch" -version = "10.2.1" +version = "11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "bracex" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/11/15/dc61746d8c0852f6d711ad09c774b63cf7c8211aa49e30871ac3d342b7e2/wcmatch-10.2.1.tar.gz", hash = "sha256:ecac70a5c70e62ba854b78318d3a1408e8651f8f1c96e5837743b71aa6a4fb92", size = 132497, upload-time = "2026-07-02T17:21:48.484Z" } +sdist = { url = "https://files.pythonhosted.org/packages/16/25/1da725838132221e33568973da484ff43813662ccc06ebf7f6e3abddfcd5/wcmatch-11.0.tar.gz", hash = "sha256:55d95c2447789712774b198ceec72939e88b5618f1f8f0a9b605bf7740b63b96", size = 141360, upload-time = "2026-07-10T05:50:24.183Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/ba/20b48eedeab5316bf9a502bb9eb7e3b1588bd61d0f565822fefa8f06e10b/wcmatch-10.2.1-py3-none-any.whl", hash = "sha256:2d775395b93f233af66690f62cb9d52b084ec159a31cc4084f4069d72f437acd", size = 39763, upload-time = "2026-07-02T17:21:47.134Z" }, + { url = "https://files.pythonhosted.org/packages/28/12/f38b6fee116274d7221743caab07d765032e1370bb54cad8714f87aeb0e8/wcmatch-11.0-py3-none-any.whl", hash = "sha256:3a5977ace27e075eef67eb03d539563f1a19018b62881949a42932cf66926934", size = 42914, upload-time = "2026-07-10T05:50:22.995Z" }, ] [[package]] diff --git a/adapters/hermes/README.md b/adapters/hermes/README.md index 1481e947..7e8ecb57 100644 --- a/adapters/hermes/README.md +++ b/adapters/hermes/README.md @@ -9,23 +9,26 @@ This adapter runs Hermes Agent through its Python SDK. ## Install -To install just the Hermes Agent adapter by itself: - -```bash -pip install "nemo-fabric[hermes]" -``` - -To install the Hermes Agent adapter along with the NeMo Fabric Runtime: - -```bash -pip install "nemo-fabric[hermes, runtime]" -``` - -To install the Hermes Agent adapter along with a compatible version of Hermes Agent: - -```bash -pip install "nemo-fabric[hermes, hermes-agent]" -``` +Hermes Agent and this adapter require Python 3.11 through 3.13. The following +table shows which components each installation provides: + +| Installation | Runtime | Adapter | Harness | NeMo Relay Python Package | +| --- | --- | --- | --- | --- | +| `pip install "nemo-fabric[hermes-agent]"` | Yes | Yes | Yes | No | +| `pip install "nemo-fabric[hermes-agent,relay]"` | Yes | Yes | Yes | Yes | +| `pip install "nemo-fabric-adapters-hermes[harness]"` | No | Yes | Yes | No | +| `pip install "nemo-fabric-adapters-hermes[full]"` | No | Yes | Yes | Yes | +| `pip install "nemo-fabric-adapters-hermes[relay]"` | No | Yes | No | Yes | +| `pip install nemo-fabric-adapters-hermes` | No | Yes | No | No | + +For an environment-managed harness, use `hermes-agent>=0.17.0`. For split +runtime and adapter environments, configure `ADAPTER_PYTHON` or +`harness.settings.python` and use matching NeMo Fabric release versions. Refer +to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-an-adapter-and-harness-without-the-runtime). + +Relay is optional for ordinary runs. Relay telemetry and +`Runtime.invoke_stream()` require one of the installations in the table that +includes the NeMo Relay Python package. ## What It Maps @@ -72,8 +75,8 @@ Keep `fabric-adapter.json` aligned with the Python implementation: - `adapter_kind` is `python` because NeMo Fabric can invoke it through Python. - `runner.module` names the persistent host module that NeMo Fabric invokes with `python -m`. -- `requirements` powers `fabric doctor`; keep required env vars, binaries, or - packages current. +- `requirements` supplies dependency checks to NeMo Fabric diagnostics; keep + required env vars, binaries, or packages current. - `config.accepts` must match the NeMo Fabric sections this adapter maps into Hermes Agent. - `telemetry.providers` declares provider-specific outputs and integration modes the adapter can produce or forward. diff --git a/adapters/hermes/pyproject.toml b/adapters/hermes/pyproject.toml index 0cc58fb2..32c94ca8 100644 --- a/adapters/hermes/pyproject.toml +++ b/adapters/hermes/pyproject.toml @@ -27,7 +27,18 @@ readme = "README.md" requires-python = ">=3.11,<3.14" dependencies = [ "nemo-fabric-adapters-common == 0.1.0", - "pyyaml>=6.0", # needed for writing hermes config files +] + +[project.optional-dependencies] +harness = [ + "hermes-agent>=0.17.0; python_version < '3.14'", +] +relay = [ + "nemo-relay>=0.6.0,<0.7", +] +full = [ + "hermes-agent>=0.17.0; python_version < '3.14'", + "nemo-relay>=0.6.0,<0.7", ] [project.urls] diff --git a/adapters/hermes/uv.lock b/adapters/hermes/uv.lock index 2809511b..52d0cae3 100644 --- a/adapters/hermes/uv.lock +++ b/adapters/hermes/uv.lock @@ -2,6 +2,545 @@ version = 1 revision = 3 requires-python = ">=3.11, <3.14" +[[package]] +name = "annotated-doc" +version = "0.0.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/8e/38aa427ed5402449e226975b649c5dc73ccadfefeb95e6aecb8f8ea4b6b6/annotated_doc-0.0.5.tar.gz", hash = "sha256:c7e58ce09192557605d8bbd92836d7e1d520ac9580096042c0bfd197efacf1bb", size = 10758, upload-time = "2026-07-28T13:50:58.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl", hash = "sha256:117bac03a25ede5df5440e855b32d556049ca169ead221505badf432fed4b101", size = 5302, upload-time = "2026-07-28T13:50:57.239Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/56/a8120250d128bed162cd73c76d45f6ef9991f3e068f62a8ee060afa3104a/annotated_types-0.8.0.tar.gz", hash = "sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7", size = 15893, upload-time = "2026-07-23T20:16:13.995Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl", hash = "sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0", size = 13427, upload-time = "2026-07-23T20:16:12.938Z" }, +] + +[[package]] +name = "anyio" +version = "4.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" }, +] + +[[package]] +name = "certifi" +version = "2026.5.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" }, +] + +[[package]] +name = "cffi" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/5f/ff100cae70ebe9d8df1c01a00e510e45d9adb5c1fdda84791b199141de97/cffi-2.1.0.tar.gz", hash = "sha256:efc1cdd798b1aaf39b4610bba7aad28c9bea9b910f25c784ccf9ec1fa719d1f9", size = 531036, upload-time = "2026-07-06T21:34:30.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/67/85c89a59ba36a671e79638f44d466749f08179266a57e4f2ffdf92174072/cffi-2.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:02cb7ff33ded4f1532476731f89ede53e2e488a8e6205515a82144246ffa7dcc", size = 183845, upload-time = "2026-07-06T21:32:26.32Z" }, + { url = "https://files.pythonhosted.org/packages/ea/dd/e3b0baa2d3d6a857ac72b7efbf18e32e487c9cdafcc13049ad765495b15e/cffi-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f5bce581e6b8c235e566a14768a943b172ada3ed73537bb0c0be1edee312d4e7", size = 184186, upload-time = "2026-07-06T21:32:28.025Z" }, + { url = "https://files.pythonhosted.org/packages/65/68/9f3ef890cf3c6ab97bd531c5677f67613d302165d16f8142b2811782a614/cffi-2.1.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:30b65779d598c370374fefabf138d456fd6f3216bfa7bedfab1ba82025b0cd93", size = 211892, upload-time = "2026-07-06T21:32:29.565Z" }, + { url = "https://files.pythonhosted.org/packages/22/d7/1a74539db16d8bfd839ff1515948948efbb162e574650fd3d846896eea95/cffi-2.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88023dfe18799507b73f1dbb0d14326a17465de1bc9c9c7655c22845e9ddc3a2", size = 218793, upload-time = "2026-07-06T21:32:30.951Z" }, + { url = "https://files.pythonhosted.org/packages/ec/d1/9a5b7169499e8e8d8e636de70b97ac7c9447104d2ff1a2cd94790cea5162/cffi-2.1.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:0a96b74cda968eebbad56d973efe5098974f0a9fb323865bf99ea1fd24e3e64c", size = 205737, upload-time = "2026-07-06T21:32:32.216Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b0/e131a9c41f10607926278453d9596163594fe1c4ebc46efe3b5e5b34eb84/cffi-2.1.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:a5781494d4d400a3f47f8f1da94b324f6e6b440a53387774002890a2a2f4b50f", size = 204909, upload-time = "2026-07-06T21:32:33.655Z" }, + { url = "https://files.pythonhosted.org/packages/fb/d2/4398416cd699b35167947c6e22aca52c47e69ad5695073c9f1f2c52e04aa/cffi-2.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aa7a1b53a2a4452ada2d1b5dade9960b2522f1e61293a811a077439e39029565", size = 217883, upload-time = "2026-07-06T21:32:35.173Z" }, + { url = "https://files.pythonhosted.org/packages/a2/a5/d4fe77b589e5e82d43ebc809bf2e6474afe8e48e32ea050b9357645b6471/cffi-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d8272c0e483b024e1b9ad029821470ed8ec65631dbd90217469da0e7cd89f1c", size = 221251, upload-time = "2026-07-06T21:32:36.527Z" }, + { url = "https://files.pythonhosted.org/packages/22/f0/a2fc43084c0433caf7f461bccc013e28f848d04ee1c5ed7fce71423cf4d9/cffi-2.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7762faa47e8ff7eb80bd261d9a7d8eea2d8baa69de5e95b70c1f338bbe712f02", size = 214250, upload-time = "2026-07-06T21:32:37.852Z" }, + { url = "https://files.pythonhosted.org/packages/04/8c/b925975448cf20634a9fbd5efceb807219db452653648d2897c0989cab2d/cffi-2.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:89095c1968b4ba8285840e131bf2891b09ae137fe2146905acae0354fbce1b5e", size = 219441, upload-time = "2026-07-06T21:32:39.146Z" }, + { url = "https://files.pythonhosted.org/packages/eb/da/5c4918a2d61d86fa927d716cb3d8e4626ef8dc8f605a599d32f33897f59a/cffi-2.1.0-cp311-cp311-win32.whl", hash = "sha256:64c753a0f87a256020004f37a1c8c02c480e725f910f0b2a0f3f07debd1b2479", size = 174496, upload-time = "2026-07-06T21:32:40.467Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c8/6c2de1d55cf35ef8b92885d5ef280790f0fb9634d87ea1cc315176aecd61/cffi-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:4f26194e3d95e06501b942642855aed4f953d55e95d7d01b7c4483db3ecff458", size = 185113, upload-time = "2026-07-06T21:32:41.761Z" }, + { url = "https://files.pythonhosted.org/packages/9e/4e/e8d7cb5783f1841a3c8fb3a7735838d7484d08ec08c9f984b14cac1ac0e9/cffi-2.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:35aaea0c7ee0e58a5cd8c2fd1a48fdf7ece0d2699b7ecdda08194e9ce5dd9b3d", size = 179927, upload-time = "2026-07-06T21:32:42.961Z" }, + { url = "https://files.pythonhosted.org/packages/1e/85/990925db5df586ec90beb97529c853497e7f85ba0234830447faf41c3057/cffi-2.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:df2b82571a1b30f58a87bf4e5a9e78d2b1eff6c6ce8fd3aa3757221f93f0863f", size = 184829, upload-time = "2026-07-06T21:32:44.324Z" }, + { url = "https://files.pythonhosted.org/packages/4b/92/e7bb136ad6b5352603732cf907ef862ca103f20f2031c1735a46300c20c9/cffi-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78474632761faa0fb96f30b1c928c84ebcf68713cbb80d15bab09dfe61640fde", size = 184728, upload-time = "2026-07-06T21:32:45.683Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c0/d1ec30ffb370f748f2fb54425972bfef9871e0132e82fb589c46b6676049/cffi-2.1.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:5972433ad71a9e46516584ef60a0fda12d9dc459938d1539c3ddecf9bdc1368d", size = 214815, upload-time = "2026-07-06T21:32:48.557Z" }, + { url = "https://files.pythonhosted.org/packages/1b/dc/5620cf930688be01f2d673804291de757a934c90b946dbdc3d84130c2ea4/cffi-2.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b6422532152adf4e59b110cb2808cee7a033800952f5c036b4af047ee43199e7", size = 222429, upload-time = "2026-07-06T21:32:49.848Z" }, + { url = "https://files.pythonhosted.org/packages/4b/a4/77b53abbf7a1e0beb9637edbef2a94d15f9c822f591e85d439ffd91519a6/cffi-2.1.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:46b1c8db8f6122420f32d02fffb924c2fe9bc772d228c7c711748fff56aabb2b", size = 210315, upload-time = "2026-07-06T21:32:51.221Z" }, + { url = "https://files.pythonhosted.org/packages/58/0c/f528df19cc94b675087324d4760d9e6d5bfae97d6217aa4fac43de4f5fcc/cffi-2.1.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9fafc5aa2e2a39aaf7f8cc0c1f044a9b07fca12e558dca53a3cc5c654ad67a7", size = 208859, upload-time = "2026-07-06T21:32:52.512Z" }, + { url = "https://files.pythonhosted.org/packages/62/f2/c9522a81c32132799a1972c39f5c5f8b4c8b9f00488a23feaa6c06f07741/cffi-2.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1e9f50d192a3e525b15a75ab5114e442d83d657b7ec29182a991bc9a88fd3a66", size = 221844, upload-time = "2026-07-06T21:32:53.704Z" }, + { url = "https://files.pythonhosted.org/packages/6e/28/bd53988b9833e8f8ad539d26f4c07a6b3f6bcb1e9e02e7ca038250b3428d/cffi-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98fff996e983a36d3aa2eca83af40c5821202e7e6f32d13ae94e3d2286f10cfe", size = 225287, upload-time = "2026-07-06T21:32:54.907Z" }, + { url = "https://files.pythonhosted.org/packages/79/99/0d0fd37f055224085f42bbb2c022d002e17dde4a97972822327b07d84101/cffi-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:379de10ce1ba048b1448599d1b37b24caee16309d1ac98d3982fc997f768700b", size = 223681, upload-time = "2026-07-06T21:32:56.329Z" }, + { url = "https://files.pythonhosted.org/packages/b0/80/c138990aa2a70b1a269f6e06348729836d733d6f970867943f61d367f8cc/cffi-2.1.0-cp312-cp312-win32.whl", hash = "sha256:9b8f0f26ca4e7513c534d351eca551947d053fac438f2a04ac96d882909b0d3a", size = 175269, upload-time = "2026-07-06T21:32:57.777Z" }, + { url = "https://files.pythonhosted.org/packages/a8/eb/f636456ff21a83fc13c032b58cc5dde061691546ac79efa284b2989b7982/cffi-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:c97f080ea627e2863524c5af3836e2270b5f5dfff1f104392b959f8df0c5d384", size = 185881, upload-time = "2026-07-06T21:32:59.253Z" }, + { url = "https://files.pythonhosted.org/packages/dd/2c/400ea43e721727dca8a65c4521390e9196757caba4a45643acb2b63271b8/cffi-2.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:6d194185eabd279f1c05ebe3504265ddfc5ad2b58d0714f7db9f01da592e9eb6", size = 180088, upload-time = "2026-07-06T21:33:02.278Z" }, + { url = "https://files.pythonhosted.org/packages/96/88/a996879e2eeccb815f6e3a5967b12a308257412acec882039d386bd2aa7b/cffi-2.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:10537b1df4967ca26d21e5072d7d54188354483b91dc75058968d3f0cf13fbda", size = 194331, upload-time = "2026-07-06T21:33:03.697Z" }, + { url = "https://files.pythonhosted.org/packages/58/85/7ae00d5c8dd6266f4e944c3db630f3c5c9a98b61d469c714d848b1d8138a/cffi-2.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a95b05f9baf29b91171b3a8bd2020b028835243e7b0ff6bb23e2a3c228518b1b", size = 196966, upload-time = "2026-07-06T21:33:05.353Z" }, + { url = "https://files.pythonhosted.org/packages/8c/e9/45c3a76ad8d43ad9261f4c95436da61128d3ca545d72b9612c0ab5be0b1c/cffi-2.1.0-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:15faec4adfff450819f3aee0e2e02c812de6edb88203aa58807955db2003472a", size = 184795, upload-time = "2026-07-06T21:33:06.699Z" }, + { url = "https://files.pythonhosted.org/packages/84/4c/82f132cb4418ee6d953d982b19191e87e2a6372c8a4ce36e50b69d6ade4a/cffi-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:716ff8ec22f20b4d988b12884086bcef0fc99737043e503f7a3935a6be99b1ea", size = 184746, upload-time = "2026-07-06T21:33:08.071Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1c/4ed5a0e5bdca6cbc275556de3328dd1b76fd0c11cc13c88fe66d1d8715f2/cffi-2.1.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:63960549e4f8dc41e31accb97b975abaecfc44c03e396c093a6436763c2ea7db", size = 214747, upload-time = "2026-07-06T21:33:09.671Z" }, + { url = "https://files.pythonhosted.org/packages/3a/a6/e879bb68cc23a2bc9ba8f4b7d8019f0c2694bad2ab6c4a3701d429439f58/cffi-2.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ff067a8d8d880e7809e4ac88eb009bb848870115317b306666502ccad30b147f", size = 222392, upload-time = "2026-07-06T21:33:10.896Z" }, + { url = "https://files.pythonhosted.org/packages/88/f6/01890cfd63c08f8eb96a8319b0443690197d240a8bd6346048cf7bde9190/cffi-2.1.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:3b926723c13eba9f81d2ef3820d63aeceec3b2d4639906047bf675cb8a7a500d", size = 210285, upload-time = "2026-07-06T21:33:12.251Z" }, + { url = "https://files.pythonhosted.org/packages/a6/cf/2b684132056f438567b61e19d690dd31cd0921ace051e0a458be6074369e/cffi-2.1.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:47ff3a8bfd8cb9da1af7524b965127095055654c177fcfc7578debcb015eecd0", size = 208801, upload-time = "2026-07-06T21:33:13.617Z" }, + { url = "https://files.pythonhosted.org/packages/6f/08/f2e7d62c460faae0926f2d6e423694aa409ced3bc1fe2927a0a6e5f05416/cffi-2.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:799416bae98336e400981ff6e532d67d5c709cfb30afb79865a1315f94b0e224", size = 221808, upload-time = "2026-07-06T21:33:15.466Z" }, + { url = "https://files.pythonhosted.org/packages/38/37/04f54b8e63a02f3d908332c9effbf8c366167c6f733ed8a3d4f79b7e2a1e/cffi-2.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:961be50688f7fba2fa65f63712d3b9b341a22311f5253460ce933f52f0de1c8c", size = 225241, upload-time = "2026-07-06T21:33:16.869Z" }, + { url = "https://files.pythonhosted.org/packages/a9/d6/c72eecca433cd3e681c65ed313ab4835d9d4a379704d0f628a6a05f51c2e/cffi-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bf5c6cf48238b0eb4c086978c492ad1cbc22373fc5b2d7353b3a598ce6db887a", size = 223588, upload-time = "2026-07-06T21:33:18.239Z" }, + { url = "https://files.pythonhosted.org/packages/c6/4b/e706f67279140f92939da3475ad610df18bfd52d50f14953a8e5fede71d5/cffi-2.1.0-cp313-cp313-win32.whl", hash = "sha256:db3eb7d46527159a878ec3460e9d40615bc25ba337d477db681aea6e4f05c5d2", size = 175248, upload-time = "2026-07-06T21:33:19.799Z" }, + { url = "https://files.pythonhosted.org/packages/5a/47/59eb7975cb0e4ef0afa764ea945b29a5bb4537a9f771cb7d6c8a5dd74c95/cffi-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:8e74a6135550c4748af665b1b1118b6aab33b1fc6a16f9aff630af107c3b4512", size = 185717, upload-time = "2026-07-06T21:33:21.47Z" }, + { url = "https://files.pythonhosted.org/packages/5a/af/34fee85c48f8d94efc8597bc09470c9dd274c145f1c12e0fbc6ab6d38d74/cffi-2.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:2282cd5e38aa8accd03e99d1256af8411c84cdbee6a89d841b563fdbd1f3e50f", size = 180114, upload-time = "2026-07-06T21:33:22.515Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/2a/23f34ec9d04624958e137efdc394888716353190e75f25dd22c7a2c7a8aa/charset_normalizer-3.4.9.tar.gz", hash = "sha256:673611bbd43f0810bec0b0f028ddeaaa501190339cac411f347ac76917c3ae7b", size = 152439, upload-time = "2026-07-07T14:34:58.454Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/e3/85ec501f206fb049259288c1f3506e53876937fb00edb47009348e66756b/charset_normalizer-3.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0e94703ec9684807f20cfb5eed95c70f67f2a8f21ad620146d7b5a13677b93e5", size = 317075, upload-time = "2026-07-07T14:32:56.021Z" }, + { url = "https://files.pythonhosted.org/packages/c3/69/2a5385192e67175f7d8bd5ce4f57c24bc956439adeae5c13a99aa28a53d1/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a441ea71902098ffe78c5abe6c494f44160b4af614ed16c3d9a3b1d17fd8ee2", size = 213837, upload-time = "2026-07-07T14:32:57.78Z" }, + { url = "https://files.pythonhosted.org/packages/b3/46/03ddc7da576d814fe0a36dd1f0fd3258e95404b4b2e3c026b7923d7e133f/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:304b13570067b2547562e308af560b3963857b1fa90bd6afd978130130fe2d6a", size = 235503, upload-time = "2026-07-07T14:32:59.205Z" }, + { url = "https://files.pythonhosted.org/packages/4e/6e/de0229a7ef40f6f9d28a837eebf4ec47bdca5dab4e900c84f22919af636a/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4773092f8019072343a7447203308b176e10199920eb02d6195e81bbb3274c29", size = 229944, upload-time = "2026-07-07T14:33:00.803Z" }, + { url = "https://files.pythonhosted.org/packages/a5/34/49b9060e8418b14fb5cba9cf6bfb383111e2538a03a1fb18e66a95aeb3d5/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:04ce310cb89c15df659582aee80a0603788732a5e017d5bd5c81158106ce249c", size = 221276, upload-time = "2026-07-07T14:33:02.199Z" }, + { url = "https://files.pythonhosted.org/packages/44/95/80282cce0fae9c3061203d723ee87da996aed79679e65d8935050ee7ca1f/charset_normalizer-3.4.9-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:c0323c9daef75ef2e5083624b4585018a0c9d5e3b40f607eed81a311270b934b", size = 205260, upload-time = "2026-07-07T14:33:03.698Z" }, + { url = "https://files.pythonhosted.org/packages/0c/74/2f62c8821b969ea3bd67cc2e6976834f48ca5d12664d2559ebcd9bcfbed7/charset_normalizer-3.4.9-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:871ff67ea1aad4dfd91736464934d56b32dac49f9fbe16cddba36198a7b3a0db", size = 217786, upload-time = "2026-07-07T14:33:05.12Z" }, + { url = "https://files.pythonhosted.org/packages/d9/8d/feabb82cb49fcad14515b1d7d1ca4787b0da7fc723a212bf89bc9e0fac52/charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:67830fc78e67501f47bb950471b2dcb9b35b140084429318e862895a8e89c993", size = 216798, upload-time = "2026-07-07T14:33:06.629Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ff/c946d63bc3786d5b84d960b0f7ab7e25b828486a946b5aa997625bcaf6a6/charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3d92613ec25e43b05f042302531ec0f00b8445190e43325880cbd6ab7c2581da", size = 206429, upload-time = "2026-07-07T14:33:08.006Z" }, + { url = "https://files.pythonhosted.org/packages/af/ba/5e5007c370702f85d2ef75791fac7943ed41e080364a673b20142e430e3e/charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:280081916dc341820640489a66e4696049401ef1cf6dd672f672e70ad915aca3", size = 223066, upload-time = "2026-07-07T14:33:09.783Z" }, + { url = "https://files.pythonhosted.org/packages/83/d5/9096aa3cf532dfad237861544eb47a0f20d5adbf1039760fed8eaae935d9/charset_normalizer-3.4.9-cp311-cp311-win32.whl", hash = "sha256:ac351b3b8014eead140e77e9717e2992c6bbe30b63bc3422422eb84865412e3d", size = 150456, upload-time = "2026-07-07T14:33:11.217Z" }, + { url = "https://files.pythonhosted.org/packages/ed/a1/e29995109e455dc8eff8d0fac6ae509be39561318a7cfeac5d33ad029213/charset_normalizer-3.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:6366a16e1a25018694d6a5d784d09b046edc9eac40ea2b54065c3052672516a1", size = 161410, upload-time = "2026-07-07T14:33:12.743Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8d/1569f4d0032d6ba2a4fe4591c35bf87868c600c41a71eb5c2e1ffa8464c2/charset_normalizer-3.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:1d22856ffbe153a602df38e4a5464f0b748a54002e0d69ac6d2ad0a197cc99ec", size = 152649, upload-time = "2026-07-07T14:33:14.173Z" }, + { url = "https://files.pythonhosted.org/packages/70/4a/ecbd131485c07fcdfad54e28946d513e3da22ef3b4bd854dcafae54ec739/charset_normalizer-3.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:45b0cc4e3556cd875e09102988d1ab8356c998b596c9fced84547c8138b487a0", size = 319300, upload-time = "2026-07-07T14:33:15.666Z" }, + { url = "https://files.pythonhosted.org/packages/ec/96/5d9364e3342d69f3a045e1777bc47c85c383e6e9466d561b33fdb419d1f9/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b2aff1c7b3884512b9512c3eaadd9bab39fb45042ffaaa1dd08ff2b9f8109d9", size = 215802, upload-time = "2026-07-07T14:33:17.031Z" }, + { url = "https://files.pythonhosted.org/packages/4b/4c/5361f9aa7f2cb58d94f2ab831b3d493f69efb1d239654b4744e3c09527cb/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9104ed0bd76a429d46f9ec0dbc9b08ad1d2dcdf2b00a5a0daa1c145329b35b44", size = 237171, upload-time = "2026-07-07T14:33:18.576Z" }, + { url = "https://files.pythonhosted.org/packages/50/78/ce342ca4ff30b2eb49fe6d9578df85974f90c67d294113e94efdd9664cbd/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b86a2b16095d250c6f58b3d9b2eee6f4147754344f3dab0922f7c9bf7d226c9", size = 233075, upload-time = "2026-07-07T14:33:20.084Z" }, + { url = "https://files.pythonhosted.org/packages/01/c4/4fa4c8b3097a11f3c5f09a35b72ed6855fb1d332469504962ab7bafcc702/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e226f6218febc71f6c1fc2fafb91c226f75bdc1d8fb12d66823716e891608fd", size = 224256, upload-time = "2026-07-07T14:33:21.747Z" }, + { url = "https://files.pythonhosted.org/packages/87/3a/ad914516df7e358a81aae018caa5e0470ba827fa6d763b1d2e87d920a5f6/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:90c44bc373b7687f6948b693cceaea1348ae0975d7474746559494468e3c1d84", size = 208784, upload-time = "2026-07-07T14:33:23.313Z" }, + { url = "https://files.pythonhosted.org/packages/d7/74/3c12f9755717dfe5c5c87da63f35d765fa0c00382ec26bf23f7fae34f2ba/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cdef90ae47919cae358d8ab15797a800ed41da7aba5d72419fb510729e2ed4b", size = 219928, upload-time = "2026-07-07T14:33:24.814Z" }, + { url = "https://files.pythonhosted.org/packages/33/9a/895095b83e7907abd6d3d99aad3a38ad0d9686cc186cb0c94c24320fe63e/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:60f44ade2cf573dad7a277e6f8ca9a51a21dda572b13bd7d8539bb3cd5dbedde", size = 218489, upload-time = "2026-07-07T14:33:26.42Z" }, + { url = "https://files.pythonhosted.org/packages/a1/34/ef5c05f412f42520d7709b7d3784d19640839eb7366ded1755511585429f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a1786910334ed46ab1dd73222f2cd1e05c2c3bb39f6dddb4f8b36fc382058a39", size = 210267, upload-time = "2026-07-07T14:33:27.952Z" }, + { url = "https://files.pythonhosted.org/packages/83/dc/9b29fa4412b318bf3bfea985c35d67eb55e04b59a7c3f2237168b0e0be6f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03d07803992c6c7bbc976327f34b18b6160327fc81cb82c9d504720ac0be3b62", size = 226030, upload-time = "2026-07-07T14:33:29.397Z" }, + { url = "https://files.pythonhosted.org/packages/0e/42/6dbc00b8cd16011691203e33570fa42ed5746599a2e878112d16eab403a3/charset_normalizer-3.4.9-cp312-cp312-win32.whl", hash = "sha256:78841cccf1af7b40f6f716338d50c0902dbe88d9f800b3c973b7a9a0a693a642", size = 151185, upload-time = "2026-07-07T14:33:30.781Z" }, + { url = "https://files.pythonhosted.org/packages/80/cc/f920afd1a23c58ccd53c1d36085a71893a4737ff5e66e0371efab6809850/charset_normalizer-3.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:4b3dac63058cc36820b0dd072f89898604e2d39686fe05321729d00d8ac185a0", size = 162557, upload-time = "2026-07-07T14:33:32.176Z" }, + { url = "https://files.pythonhosted.org/packages/f0/e6/0386d43a261ff4e4b30c5857af7df877254b46bec7b9d1b74b6bf969a90b/charset_normalizer-3.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:78fa18e436a1a0e58dbd7e02fc4473f3f32cceb12df9dfca542d075961c307d2", size = 152665, upload-time = "2026-07-07T14:33:33.711Z" }, + { url = "https://files.pythonhosted.org/packages/b2/06/97ec2aeae780b31d742b6352218b43841a6871e2564578ca522dce4a45c3/charset_normalizer-3.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:440eede837960000d74978f0eba527be106b5b9aee0daf779d395276ed0b0614", size = 317688, upload-time = "2026-07-07T14:33:35.408Z" }, + { url = "https://files.pythonhosted.org/packages/d0/39/8ff066c672434225f8d25f8b739f992af250944392173dcc88362681c9bf/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21e764fd1e70b6a3e205a0e46f3051701f98a8cb3fad66eeb80e48bb502f8698", size = 214982, upload-time = "2026-07-07T14:33:36.996Z" }, + { url = "https://files.pythonhosted.org/packages/92/8f/3a47a3667c83c2df9483d91644c6c107de3bf8874aa1793da9d3012eb986/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e4fd89cc178bced6ad29cb3e6dd4aa63fa5017c3524dbd0b25998fb64a87cc8b", size = 236460, upload-time = "2026-07-07T14:33:38.536Z" }, + { url = "https://files.pythonhosted.org/packages/f1/60/b22cdbee7e4013dab8b0d7647fc6181120fbbbc8f7025c226d15bd5a47fc/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bd47ba7fc3ca94896759ea0109775132d3e7ab921fbf54038e1bab2e46c313c9", size = 232003, upload-time = "2026-07-07T14:33:40.059Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f8/72eb13dcabe7257035cea8aefd922caad2f110d252bf9f67c4c2ca763aee/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:84fd18bcc17526fc2b3c1af7d2b9217d32c9c04448c16ec693b9b4f1985c3d33", size = 223149, upload-time = "2026-07-07T14:33:41.631Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3e/faee8f9de92b14ee1198e9163252bb15efee7301b31256a3b6d9ebfdd0dd/charset_normalizer-3.4.9-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:5b10cd92fc5c498b35a8635df6d5a100207f88b63a4dc1de7ef9a548e1e2cd63", size = 207901, upload-time = "2026-07-07T14:33:43.209Z" }, + { url = "https://files.pythonhosted.org/packages/3a/25/45f30093ae27dd7b92a793b61882a38685f993700113ca36e0c9c14965e1/charset_normalizer-3.4.9-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a4fbdde9dd4a9ce5fd52c2b3a347bb50cc89483ef783f1cb00d408c13f7a96c0", size = 219176, upload-time = "2026-07-07T14:33:44.725Z" }, + { url = "https://files.pythonhosted.org/packages/48/18/c8f397329c35e32f6a837e488986f4ae03bd2abebc453b48714991630c2f/charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:416c229f77e5ea25b3dfd4b582f8d73d7e43c22320302b9ab128a2d3a0b38efe", size = 217356, upload-time = "2026-07-07T14:33:46.192Z" }, + { url = "https://files.pythonhosted.org/packages/86/7e/5ce0bba863470fd1902d5e5843968951bddf38abe4742fc97116ef4598b3/charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:75286256590a6320cf106a0d28970d3560aad9ee09aa7b34fb40524792436d35", size = 209614, upload-time = "2026-07-07T14:33:47.705Z" }, + { url = "https://files.pythonhosted.org/packages/6c/ef/2473d3c4d869155be4af1191111d59c4d5c4e0173026f7e85b176e23bf65/charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:69b157c5d3292bcd443faca052f3096f637f1e074b98212a933c074ae23dc3b8", size = 224991, upload-time = "2026-07-07T14:33:49.238Z" }, + { url = "https://files.pythonhosted.org/packages/d0/a3/53ddae3db108a088156aa8ddfafd411ebbc1340f48c5573f697b27f69a39/charset_normalizer-3.4.9-cp313-cp313-win32.whl", hash = "sha256:51307f5c71007673a2bf8232ad973483d281e74cb99c8c5a990af1eefa6277d9", size = 150622, upload-time = "2026-07-07T14:33:50.711Z" }, + { url = "https://files.pythonhosted.org/packages/e8/ef/6953a77c7cf2c2ff9998e6f575ab3e380119f100223381565a4f94c1f836/charset_normalizer-3.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:fe2c7201c642b7c308f1675355ad7ff7b66acfe3541625efe5a3ad38f29d6115", size = 161947, upload-time = "2026-07-07T14:33:52.197Z" }, + { url = "https://files.pythonhosted.org/packages/6e/fb/d560d1d1555debbfe7849d9cac6145c1b537709d79576bf22557ed803b82/charset_normalizer-3.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:611057cc5d5c0afc743ba8be6bd828c17e0aaa8643f9d0a9b9bb7dea80eb8012", size = 152594, upload-time = "2026-07-07T14:33:53.486Z" }, + { url = "https://files.pythonhosted.org/packages/98/2b/f97f1c193fb855c345d678f5077d6926034db0722df74c8f057020e05a25/charset_normalizer-3.4.9-py3-none-any.whl", hash = "sha256:68e5f26a1ad57ded6d1cfb85331d1c1a195314756471d97758c48498bb4dcdf5", size = 64538, upload-time = "2026-07-07T14:34:56.993Z" }, +] + +[[package]] +name = "click" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", size = 338000, upload-time = "2026-06-24T17:45:15.148Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl", hash = "sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76", size = 119243, upload-time = "2026-06-24T17:45:13.73Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "concurrent-log-handler" +version = "0.9.29" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "portalocker" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9c/2c/ba185acc438cff6b58cd8f8dec27e7f4fcabf6968a1facbb6d0cacbde7fe/concurrent_log_handler-0.9.29.tar.gz", hash = "sha256:bc37a76d3f384cbf4a98f693ebd770543edc0f4cd5c6ab6bc70e9e1d7d582265", size = 42114, upload-time = "2026-02-22T18:18:25.758Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/f3/3e3188fdb3e53c6343fd1c7de41c55d4db626f07db3877eae77b28d58bd2/concurrent_log_handler-0.9.29-py3-none-any.whl", hash = "sha256:0d6c077fbaef2dae49a25975dcf72a602fe0a6a4ce80a3b7c37696d37e10459a", size = 32052, upload-time = "2026-02-22T18:18:24.558Z" }, +] + +[[package]] +name = "croniter" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, + { name = "pytz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/2f/44d1ae153a0e27be56be43465e5cb39b9650c781e001e7864389deb25090/croniter-6.0.0.tar.gz", hash = "sha256:37c504b313956114a983ece2c2b07790b1f1094fe9d81cc94739214748255577", size = 64481, upload-time = "2024-12-17T17:17:47.32Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/4b/290b4c3efd6417a8b0c284896de19b1d5855e6dbdb97d2a35e68fa42de85/croniter-6.0.0-py2.py3-none-any.whl", hash = "sha256:2f878c3856f17896979b2a4379ba1f09c83e374931ea15cc835c5dd2eee9b368", size = 25468, upload-time = "2024-12-17T17:17:45.359Z" }, +] + +[[package]] +name = "cryptography" +version = "46.0.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", size = 750652, upload-time = "2026-04-08T01:57:54.692Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/5d/4a8f770695d73be252331e60e526291e3df0c9b27556a90a6b47bccca4c2/cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4", size = 7179869, upload-time = "2026-04-08T01:56:17.157Z" }, + { url = "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", size = 4275492, upload-time = "2026-04-08T01:56:19.36Z" }, + { url = "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", size = 4426670, upload-time = "2026-04-08T01:56:21.415Z" }, + { url = "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", size = 4280275, upload-time = "2026-04-08T01:56:23.539Z" }, + { url = "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", size = 4928402, upload-time = "2026-04-08T01:56:25.624Z" }, + { url = "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", size = 4459985, upload-time = "2026-04-08T01:56:27.309Z" }, + { url = "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de", size = 3990652, upload-time = "2026-04-08T01:56:29.095Z" }, + { url = "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", size = 4279805, upload-time = "2026-04-08T01:56:30.928Z" }, + { url = "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", size = 4892883, upload-time = "2026-04-08T01:56:32.614Z" }, + { url = "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", size = 4459756, upload-time = "2026-04-08T01:56:34.306Z" }, + { url = "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", size = 4410244, upload-time = "2026-04-08T01:56:35.977Z" }, + { url = "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", size = 4674868, upload-time = "2026-04-08T01:56:38.034Z" }, + { url = "https://files.pythonhosted.org/packages/1a/bb/a5c213c19ee94b15dfccc48f363738633a493812687f5567addbcbba9f6f/cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457", size = 3026504, upload-time = "2026-04-08T01:56:39.666Z" }, + { url = "https://files.pythonhosted.org/packages/2b/02/7788f9fefa1d060ca68717c3901ae7fffa21ee087a90b7f23c7a603c32ae/cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b", size = 3488363, upload-time = "2026-04-08T01:56:41.893Z" }, + { url = "https://files.pythonhosted.org/packages/a7/7f/cd42fc3614386bc0c12f0cb3c4ae1fc2bbca5c9662dfed031514911d513d/cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4", size = 7165618, upload-time = "2026-04-08T01:57:10.645Z" }, + { url = "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", size = 4270628, upload-time = "2026-04-08T01:57:12.885Z" }, + { url = "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", size = 4415405, upload-time = "2026-04-08T01:57:14.923Z" }, + { url = "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", size = 4272715, upload-time = "2026-04-08T01:57:16.638Z" }, + { url = "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", size = 4918400, upload-time = "2026-04-08T01:57:19.021Z" }, + { url = "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", size = 4450634, upload-time = "2026-04-08T01:57:21.185Z" }, + { url = "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", size = 3985233, upload-time = "2026-04-08T01:57:22.862Z" }, + { url = "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", size = 4271955, upload-time = "2026-04-08T01:57:24.814Z" }, + { url = "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", size = 4879888, upload-time = "2026-04-08T01:57:26.88Z" }, + { url = "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", size = 4449961, upload-time = "2026-04-08T01:57:29.068Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", size = 4401696, upload-time = "2026-04-08T01:57:31.029Z" }, + { url = "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", size = 4664256, upload-time = "2026-04-08T01:57:33.144Z" }, + { url = "https://files.pythonhosted.org/packages/4b/fa/f0ab06238e899cc3fb332623f337a7364f36f4bb3f2534c2bb95a35b132c/cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246", size = 3013001, upload-time = "2026-04-08T01:57:34.933Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f1/00ce3bde3ca542d1acd8f8cfa38e446840945aa6363f9b74746394b14127/cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3", size = 3472985, upload-time = "2026-04-08T01:57:36.714Z" }, + { url = "https://files.pythonhosted.org/packages/63/0c/dca8abb64e7ca4f6b2978769f6fea5ad06686a190cec381f0a796fdcaaba/cryptography-46.0.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fc9ab8856ae6cf7c9358430e49b368f3108f050031442eaeb6b9d87e4dcf4e4f", size = 3476879, upload-time = "2026-04-08T01:57:38.664Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ea/075aac6a84b7c271578d81a2f9968acb6e273002408729f2ddff517fed4a/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d3b99c535a9de0adced13d159c5a9cf65c325601aa30f4be08afd680643e9c15", size = 4219700, upload-time = "2026-04-08T01:57:40.625Z" }, + { url = "https://files.pythonhosted.org/packages/6c/7b/1c55db7242b5e5612b29fc7a630e91ee7a6e3c8e7bf5406d22e206875fbd/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d02c738dacda7dc2a74d1b2b3177042009d5cab7c7079db74afc19e56ca1b455", size = 4385982, upload-time = "2026-04-08T01:57:42.725Z" }, + { url = "https://files.pythonhosted.org/packages/cb/da/9870eec4b69c63ef5925bf7d8342b7e13bc2ee3d47791461c4e49ca212f4/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:04959522f938493042d595a736e7dbdff6eb6cc2339c11465b3ff89343b65f65", size = 4219115, upload-time = "2026-04-08T01:57:44.939Z" }, + { url = "https://files.pythonhosted.org/packages/f4/72/05aa5832b82dd341969e9a734d1812a6aadb088d9eb6f0430fc337cc5a8f/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3986ac1dee6def53797289999eabe84798ad7817f3e97779b5061a95b0ee4968", size = 4385479, upload-time = "2026-04-08T01:57:46.86Z" }, + { url = "https://files.pythonhosted.org/packages/20/2a/1b016902351a523aa2bd446b50a5bc1175d7a7d1cf90fe2ef904f9b84ebc/cryptography-46.0.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:258514877e15963bd43b558917bc9f54cf7cf866c38aa576ebf47a77ddbc43a4", size = 3412829, upload-time = "2026-04-08T01:57:48.874Z" }, +] + +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, +] + +[[package]] +name = "fastapi" +version = "0.140.13" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/cb/7a4d2c2eb5a5d8a91763c05b7383d72917862e32f780daa0e27ffbb34cc6/fastapi-0.140.13.tar.gz", hash = "sha256:500172a08cf1459901f90b05c37d93060dada3b573fec8f0862445db52ba6b4b", size = 424843, upload-time = "2026-07-28T15:37:00.805Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/4e/f9e8c762ef5e05c40482131e3d5e8b36bca13fa127578261f1d6b35a25d4/fastapi-0.140.13-py3-none-any.whl", hash = "sha256:8b017110e1e9f30a95e8bdb8f71fbe2f0fe3af5717109e5b14f9e069df54f6d4", size = 131222, upload-time = "2026-07-28T15:37:02.124Z" }, +] + +[[package]] +name = "fire" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "termcolor" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/00/f8d10588d2019d6d6452653def1ee807353b21983db48550318424b5ff18/fire-0.7.1.tar.gz", hash = "sha256:3b208f05c736de98fb343310d090dcc4d8c78b2a89ea4f32b837c586270a9cbf", size = 88720, upload-time = "2025-08-16T20:20:24.175Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/4c/93d0f85318da65923e4b91c1c2ff03d8a458cbefebe3bc612a6693c7906d/fire-0.7.1-py3-none-any.whl", hash = "sha256:e43fd8a5033a9001e7e2973bab96070694b9f12f2e0ecf96d4683971b5ab1882", size = 115945, upload-time = "2025-08-16T20:20:22.87Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "hermes-agent" +version = "0.19.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "concurrent-log-handler", marker = "sys_platform == 'win32'" }, + { name = "croniter" }, + { name = "cryptography" }, + { name = "fastapi" }, + { name = "fire" }, + { name = "httpx", extra = ["socks"] }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "openai" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pillow" }, + { name = "prompt-toolkit" }, + { name = "psutil" }, + { name = "ptyprocess", marker = "sys_platform != 'win32'" }, + { name = "pydantic" }, + { name = "pyjwt", extra = ["crypto"] }, + { name = "python-dotenv" }, + { name = "python-multipart" }, + { name = "pywinpty", marker = "sys_platform == 'win32'" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "rich" }, + { name = "ruamel-yaml" }, + { name = "tenacity" }, + { name = "tzdata", marker = "sys_platform == 'win32'" }, + { name = "urllib3" }, + { name = "uvicorn", extra = ["standard"] }, + { name = "websockets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c1/2c/5eca471374c1b48555a8f0b988c06b19a93ae33a6c0e67845e47fc3a5628/hermes_agent-0.19.0.tar.gz", hash = "sha256:ac986bede64a2785436676c0ea084ec586574f8cb00a9d047e095b435d3e21c0", size = 14282599, upload-time = "2026-07-20T18:37:28.903Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/30/c85be8290e9565dc3c7a9720e93f3e59e09b1b163487be4946c3aa848f80/hermes_agent-0.19.0-py3-none-any.whl", hash = "sha256:bd0bac012aee38a60894781f4597dc29ee7bedb3448540249921f10d3bef327f", size = 10144439, upload-time = "2026-07-20T18:37:26.417Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httptools" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/e5/d471fcb0e14523fe1c3f4ba58ca52480e7bd70ad7109a3846bc75892f7fb/httptools-0.8.0.tar.gz", hash = "sha256:6b2a32f18d97e16e90827d7a819ffa8dbd8cc245fc4e1fa9d1095b54ef4bd999", size = 271342, upload-time = "2026-05-25T22:17:48.841Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/d2/c3eedaef57de65c3cc5f8dc244cf12d09c84ad258a479055aad6db23206c/httptools-0.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ed377e64805bdba4943c82717333f8f8603a13b09aff9cead2717c6c817fb168", size = 208428, upload-time = "2026-05-25T22:16:59.717Z" }, + { url = "https://files.pythonhosted.org/packages/f1/94/dfe435d90d0ef61ec0f2cc3d480eef78c59727c6c2ce039f433882f6131a/httptools-0.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9518c406d7b310f05adb1a37f80acabac40504a575d7c0da6d3e365c695ac20d", size = 113366, upload-time = "2026-05-25T22:17:00.795Z" }, + { url = "https://files.pythonhosted.org/packages/cc/d4/13025f1a56e615dcb331e0bbe2d9a1143212b58c263385fc5d2e558f5bac/httptools-0.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:57278e6fa0424c42a8a3e454828ab4f0aff27b40cddf9679579b98c6dce6a376", size = 464676, upload-time = "2026-05-25T22:17:02.014Z" }, + { url = "https://files.pythonhosted.org/packages/bf/95/4c1c26c0b985f8a3331682d802598f14e32dc41bf7509266eb2c04ad4801/httptools-0.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bbb8caadb2b742d293169d2b458b5c001ef70e3158704aa3d3ef9597624c5d1d", size = 464235, upload-time = "2026-05-25T22:17:03.109Z" }, + { url = "https://files.pythonhosted.org/packages/a2/82/6735be2b0ca527718c431cdb8e5f70c3862c0844a687df0f572c51e11497/httptools-0.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:52dd695b865fe96d9d2b16b64a895f3f57bf3cb064e8383cd3b5713a069e8085", size = 449809, upload-time = "2026-05-25T22:17:04.443Z" }, + { url = "https://files.pythonhosted.org/packages/b5/f9/5811c74f37a758c8a4aa3dc430375119d335947e883efc4664d8f3559a41/httptools-0.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:20b4aac66ff65f7db06a375808b78f42a94970aa22e826b3cb2b43eb09174124", size = 452174, upload-time = "2026-05-25T22:17:05.476Z" }, + { url = "https://files.pythonhosted.org/packages/cc/94/97b75870dea07b71e3ec535cebe525b08d723152e4c7d13fa887e51f4de2/httptools-0.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:a1b4c8e7a489a0d750d91894e9a8cdc295838f1924c0ca903ae993456fddec07", size = 90991, upload-time = "2026-05-25T22:17:06.75Z" }, + { url = "https://files.pythonhosted.org/packages/14/88/1d21a36da8f5cb0fa49eafd4b169eba5608d57e75bbcf61845cbc6243216/httptools-0.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:880490234c10f70a9830743097e8958d6e4b9f5a0ffc24515023afeef984054d", size = 208247, upload-time = "2026-05-25T22:17:07.843Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/cc4feea2945cb3051038f090c9b36bd5b8a9d7f5a894a506a8983e33fd1c/httptools-0.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5931891fb7b441b8a3853cf1b85c82c903defce084dd5f6771ca46e31bf862c5", size = 113064, upload-time = "2026-05-25T22:17:09.136Z" }, + { url = "https://files.pythonhosted.org/packages/e3/a6/febbb8b8db0f58b38e44ad6cb946e6a255ae49b55f2e8543408fb7501ccd/httptools-0.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b15fc622b0f869d19207c4089a501d9bcc63ca5e071ffdd2f03f922df882dcb2", size = 523851, upload-time = "2026-05-25T22:17:10.106Z" }, + { url = "https://files.pythonhosted.org/packages/b7/e4/f90a0df0b83beff265b7e3b65f2a4cefd95792d4be0ac3e16049f2acd3c2/httptools-0.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:425f83884fd6343828d8c565f046cb72b6d19063f6924093e11bcd8e1548cd09", size = 518842, upload-time = "2026-05-25T22:17:11.218Z" }, + { url = "https://files.pythonhosted.org/packages/9e/2d/0c9ac76dd2c893841fbf6498d6acec4f2442e1b7067f6e3e316a80e494e8/httptools-0.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ef7c3c97f4311c7be57e2986629df89d49cb434dbff78eafcd48c2bff986b15a", size = 501238, upload-time = "2026-05-25T22:17:12.728Z" }, + { url = "https://files.pythonhosted.org/packages/ca/42/906adc91ae3a5fa9c59c0a2f21c139725bd7e5b41ae6acd485cd14123ebf/httptools-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a1afd7c9fbff0d9f5d489c4ce2768bd09c84a46ddefc7161e6aa82ae35c85745", size = 509567, upload-time = "2026-05-25T22:17:13.842Z" }, + { url = "https://files.pythonhosted.org/packages/05/0b/4240efeb672751ee5b9b380cb0e3fdc050bc05f68adc7a8aefc4fcd9a69a/httptools-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:cd96f29b4bab1d42fa6e3d008711c75e0f79e94e06827330160e3a304227f150", size = 90918, upload-time = "2026-05-25T22:17:15.155Z" }, + { url = "https://files.pythonhosted.org/packages/5e/e5/8cfcabc5546e8022f168be28bcdaa128a240a0befdd03b59d558b4f18bd6/httptools-0.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:614ceea8ea606848bece2338ac03b3ce5324bcb4be8dc7d377ed708012fa4db8", size = 205148, upload-time = "2026-05-25T22:17:16.333Z" }, + { url = "https://files.pythonhosted.org/packages/2a/0e/0fb14848c19a686c8062ff9067c1a48793e3224b47bc5b201535b6036fce/httptools-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2d689918c15a013c65ef52d9fd495d766893ab831a2c8d89f2ac5940a5df847c", size = 111368, upload-time = "2026-05-25T22:17:17.586Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1b/46f1cecf06b9bbde8e4b8c88034ac7908989e5ff7a3a388ef38392949c1f/httptools-0.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb3028cca2fc0a6d720e52ef61d8ebb62fcbfeb1de56874546d858d3f25a26b7", size = 486447, upload-time = "2026-05-25T22:17:18.564Z" }, + { url = "https://files.pythonhosted.org/packages/77/00/258bfc0837221f81d9725c45f9b948a6a6b2994a147a4fb66e85100c668f/httptools-0.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:88bdd940f2b5d487b4d032c6afa5489a7dc4694410d43de3c38c4fb3af0dc45d", size = 482448, upload-time = "2026-05-25T22:17:19.912Z" }, + { url = "https://files.pythonhosted.org/packages/04/ab/d1cef3b5523f4d272a70f42a776c3169a2dddfe3a54de4b2ce4a36341528/httptools-0.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a43c9dd399758ccc0531acb0a3c4a6c299ee893ee9400e9c893b7bdcfae0681", size = 464460, upload-time = "2026-05-25T22:17:20.882Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/5d1d072442277bb2b3434e0e60690b8e8c23840ef7de8b6ea54040a536d3/httptools-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0770728beb05094c809b98e814edff5fef69d26ad7d21185f2f6d5884a0ba683", size = 471312, upload-time = "2026-05-25T22:17:22.085Z" }, + { url = "https://files.pythonhosted.org/packages/0d/66/b96623b27e51a68199ef4efdda0613cced9233fe3062ac74e50749c5ad37/httptools-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:7685df791fad561384bfb139e77fde27a1ffd93134e016f95a0db424ffbf77b1", size = 90117, upload-time = "2026-05-25T22:17:23.074Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[package.optional-dependencies] +socks = [ + { name = "socksio" }, +] + +[[package]] +name = "idna" +version = "3.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "jiter" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/1f/10936e16d8860c70698a1aa939a46aa0224813b782bce4e000e637da0b2d/jiter-0.16.0.tar.gz", hash = "sha256:7b24c3492c5f4f84a37946ad9cf504910cf6a782d6a4e0689b6673c5894b4a1c", size = 176431, upload-time = "2026-06-29T13:05:13.657Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/3f/fae6cc967d120ec89e31c5418a51176d8278b3087fbb384a9176754f353c/jiter-0.16.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:67fddeda1688f0cce2d2ae83ccf8a80f79936f2d2997d6cc2261f82fdb54a4d3", size = 309289, upload-time = "2026-06-29T13:02:52.301Z" }, + { url = "https://files.pythonhosted.org/packages/c8/e3/97c6c3562c077f6247d6e6ce5c82562500b6316c0d928e97e106b7a1321a/jiter-0.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c90c0f63df322be920eda6ce622e3083d8906ba267f8220fe7873213b8b4430e", size = 315181, upload-time = "2026-06-29T13:02:53.964Z" }, + { url = "https://files.pythonhosted.org/packages/7b/89/d8d073f8aa2667e46c6c0873f86fe4a512bba4293cc730f626a076211a62/jiter-0.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64c0203212098470032aabcde9356fc168f377aade3e43def61dfe17e92f2037", size = 340939, upload-time = "2026-06-29T13:02:55.412Z" }, + { url = "https://files.pythonhosted.org/packages/87/c9/db4fda3ed73fb864139305e935e5b8b38a5a24692a5a9dd356c22f1b9c8d/jiter-0.16.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12288303c9844e61e1651d02a9a6f6633e47d39f897d6991d1427161ce6b746e", size = 364932, upload-time = "2026-06-29T13:02:57.28Z" }, + { url = "https://files.pythonhosted.org/packages/a2/74/52b5e86241057f52ddd7c9a580f90effb51f9d06239f6fc612279b91a838/jiter-0.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cf109d010b4b05a105afb3d43be36a21322d345ad3111e13d15f680afef0e5b", size = 461132, upload-time = "2026-06-29T13:02:58.994Z" }, + { url = "https://files.pythonhosted.org/packages/a9/87/544a700f7447c1f31c5d7833821a4daa5683165c2d5a094fbf5b5800c3dc/jiter-0.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62c1b7fe1f77925acf5af68b6140b8810fa87dfd4dc0a9c8568ec2fa2a10429c", size = 374857, upload-time = "2026-06-29T13:03:00.455Z" }, + { url = "https://files.pythonhosted.org/packages/40/cd/0fcc3f7d39183674d5bfa9ec640faaeb506c60be7c8f94625dfba366e37c/jiter-0.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8597d23c87f59294f83bcb6229b9ed1fccee13dbba967b46930d2f1759466fee", size = 347053, upload-time = "2026-06-29T13:03:02.045Z" }, + { url = "https://files.pythonhosted.org/packages/5c/ae/c7e64e7932ad597fa395b61440b249ada6366716e25c6e08dd2afbd021e6/jiter-0.16.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:3126a5dbad56401989ac769aca0cb56005bfb3e2366eea0ca99d1a91c3c1ee03", size = 356153, upload-time = "2026-06-29T13:03:03.706Z" }, + { url = "https://files.pythonhosted.org/packages/d4/1c/1c719044f14da814e1a060191ab19b96f3e99207bc5b4bfc6d6be34b3f80/jiter-0.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c4b4717bdb35ae456f831a6b08d01880fff399887a6bbc526a583a406e484eea", size = 393956, upload-time = "2026-06-29T13:03:05.165Z" }, + { url = "https://files.pythonhosted.org/packages/3b/dc/7b2f303a2847207e265503853a2d964a55354cffd62a5f2936c155486798/jiter-0.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:adff21bc78edfe086c15eb495b900306076de378dc2337c132401fc39bd79c91", size = 521081, upload-time = "2026-06-29T13:03:06.886Z" }, + { url = "https://files.pythonhosted.org/packages/c2/5f/501cf6e1e09caeb420195179ffc6f62aca603f1220ec53fd80d0d70b3e56/jiter-0.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dab907db06fc593645e73109acf4581ba5b548897d28b9348dc41ddc8343b2d3", size = 552085, upload-time = "2026-06-29T13:03:08.339Z" }, + { url = "https://files.pythonhosted.org/packages/79/54/aa5be86520113b79455c3877f3d1f07a348098df4083ba3688e9537e52dd/jiter-0.16.0-cp311-cp311-win32.whl", hash = "sha256:560b2cf3fb03240cd34f27409a238547488708f05b7c3924f571a60422251ec7", size = 206755, upload-time = "2026-06-29T13:03:09.653Z" }, + { url = "https://files.pythonhosted.org/packages/64/ec/2feb893eb330bd69b413866f4d5daada33c3962f1c6f270c91ca2d87fdf9/jiter-0.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:e431cfc9caf44c1d5459ff77d4e64cbf85fddb6a35dad836a15c6a9ec23087c1", size = 199155, upload-time = "2026-06-29T13:03:10.979Z" }, + { url = "https://files.pythonhosted.org/packages/b9/9c/ca040d94415048a3666fc237774df8151c96f8d2b661cbe3b184acc95876/jiter-0.16.0-cp311-cp311-win_arm64.whl", hash = "sha256:2a8e9e39cf083016137aa5cadafe3188adc2ba6ba1fbf1e5d18889ad3e9ad056", size = 194403, upload-time = "2026-06-29T13:03:12.341Z" }, + { url = "https://files.pythonhosted.org/packages/83/2b/52ace16ed031354f0539749a49e4bf33797d82bea5137910835fa4b09793/jiter-0.16.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:67c3bc1760f8c99d805dcab4e644027142a53b1d5d861f18780ebdbd5d40b72a", size = 306943, upload-time = "2026-06-29T13:03:14.035Z" }, + { url = "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5af7780e4a26bd7d0d989592bf9ef12ebf806b74ab709223ecca37c749872ea9", size = 307779, upload-time = "2026-06-29T13:03:15.418Z" }, + { url = "https://files.pythonhosted.org/packages/88/6c/59bd309cab4460c54cf1079f3eb7fe7af6a4c895c5c957a53378693bad2b/jiter-0.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5bf78d0e05e45cfdd66558893938d59afe3d1b1a824a202039b20e607d25a72", size = 335826, upload-time = "2026-06-29T13:03:17.11Z" }, + { url = "https://files.pythonhosted.org/packages/3b/8c/f5ef7b65f0df47afa16596969defb281ebb86e96df346d62be6fd853d620/jiter-0.16.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4444a83f946605990c98f625cdd3d2725bfb818158760c5748c653170a20e0e", size = 362573, upload-time = "2026-06-29T13:03:18.781Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0b/ace4354da061ee38844a0c27dc2c21eecd27aea119e8da324bea987522d0/jiter-0.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a23f0e4f957e1be65752d2dfac9a5a06b1917af8dc85deb639c3b9d02e31290", size = 457979, upload-time = "2026-06-29T13:03:20.293Z" }, + { url = "https://files.pythonhosted.org/packages/55/40/c0253d3772eb9dcd8e6606ee9b2d53ec8e5b814589c47f140aa585f21eaa/jiter-0.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c22a488f7b9218e245a0025a9ba6b100e2e54700831cf4cf16833a27fba3ad01", size = 372302, upload-time = "2026-06-29T13:03:21.739Z" }, + { url = "https://files.pythonhosted.org/packages/a8/d2/4839422241aa12860ce597b20068727094ba0bc480723c74924ca5bad483/jiter-0.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46add52f4ad47a08bfb1219f3e673da972191489a33016edefdb5ea55bfa8c48", size = 343805, upload-time = "2026-06-29T13:03:23.384Z" }, + { url = "https://files.pythonhosted.org/packages/e2/59/e196888a05befdda7dbe299b722d56f2f6eec65402bc34c0a3306d595feb/jiter-0.16.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:9c8a956fd72c2cf1e730d01ea080341f13aa0a97a4a33b51abebe725b7ae9ca9", size = 351107, upload-time = "2026-06-29T13:03:24.815Z" }, + { url = "https://files.pythonhosted.org/packages/ec/74/4cd9e0fca65232136400354b630fbfcd2de634e22ccbb96567725981b548/jiter-0.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:561926e0573ffe4a32498420a76d64b16c513e1ab413b9d28158a8764ac701e5", size = 388441, upload-time = "2026-06-29T13:03:26.266Z" }, + { url = "https://files.pythonhosted.org/packages/d9/8c/554691e48bc711299c0a293dd8a6179e24b2d66a54dc295421fcf64569c0/jiter-0.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:44d019fa8cdaf89bf29c71b39e3712143fdd0ac76725c6ef954f9957a5ea8730", size = 516354, upload-time = "2026-06-29T13:03:28.02Z" }, + { url = "https://files.pythonhosted.org/packages/a4/cb/01e9d69dc2cc6759d4f91e230b34489c4fdb2518992650633f9e20bece89/jiter-0.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0df91907609837f33341b8e6fe73b95991fdaa57caf1a0fbd343dffe826f386f", size = 547880, upload-time = "2026-06-29T13:03:29.534Z" }, + { url = "https://files.pythonhosted.org/packages/79/70/2953195f1c6ad00f49fa67e13df7e60acb3dd4f387101bc15abccddd905e/jiter-0.16.0-cp312-cp312-win32.whl", hash = "sha256:51d7b836acb0108d7c77df1742332cac2a1fa04a74d6dacec46e7091f0e91274", size = 203473, upload-time = "2026-06-29T13:03:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/05/2909a8b10699a4d560f8c502b6b2c5f3991b682b1922c1eedda242b225bd/jiter-0.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:1878349266f8ee36ecb1375cc5ba2f115f35fd9f0a1a4119e725e379126647f7", size = 196905, upload-time = "2026-06-29T13:03:32.472Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a9/6b82bb1c8d7790d602489b967b982a909e5d092875a6c2ade96444c8dfc5/jiter-0.16.0-cp312-cp312-win_arm64.whl", hash = "sha256:2ed5738ae4af18271a51a528b8811b0cbfa4a1858de9d83359e4169855d6a331", size = 190618, upload-time = "2026-06-29T13:03:34.672Z" }, + { url = "https://files.pythonhosted.org/packages/91/c0/555fc60473d30d66894ba825e63615e3be7524fac23858356afa7a38906c/jiter-0.16.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:41977aa5654023948c2dae2a81cbf9c43343954bef1cd59a154dd15a4d84c195", size = 306203, upload-time = "2026-06-29T13:03:36.243Z" }, + { url = "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d28bb3c26762358dadf3e5bf0bccd29ae987d65e6988d2e6f49829c76b003c09", size = 306489, upload-time = "2026-06-29T13:03:37.846Z" }, + { url = "https://files.pythonhosted.org/packages/96/3f/02fdfc6705cad96127d883af5c34e4867f554f29ec7705ec1a46156400a9/jiter-0.16.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0542a7189c26920778658fc8fcf2af8bae05bae9924577f71804acef37996536", size = 335453, upload-time = "2026-06-29T13:03:39.221Z" }, + { url = "https://files.pythonhosted.org/packages/b2/a6/e4bda5920d4b0d7c5dfb7174ce4a6b2e4d3e11c9162c452ef0eab4cdbdbd/jiter-0.16.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8fb8de1e23a0cb2a7f53c335049c7b72b6db41aa6227cdcc0972a1de5cb39450", size = 361625, upload-time = "2026-06-29T13:03:40.597Z" }, + { url = "https://files.pythonhosted.org/packages/b7/97/4e6b59b2c6e55cbb3e183595f81ad65dcfb21c915fee5e19e335df21bc55/jiter-0.16.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b72d0b2990ca754a9102779ac98d8597b7cb31678958562214a007f909eab78e", size = 456958, upload-time = "2026-06-29T13:03:42.074Z" }, + { url = "https://files.pythonhosted.org/packages/15/e0/97e9557686d2f94f4b93786eccb7eed28e9228ad132ea8237f44727314a7/jiter-0.16.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5f91b1c27fc22a57993d5a5cb8a627cb8ed4b10502716fac1ffbfe1d19d84e8", size = 372017, upload-time = "2026-06-29T13:03:43.658Z" }, + { url = "https://files.pythonhosted.org/packages/0f/94/db768b6938e0df35c86beeba3dfbbb025c9ee5c19e1aa271f2396e50864d/jiter-0.16.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c682bea068a90b764577bdb78a60a4c1d1606daf9cd4c893832a37c7cc9d9026", size = 343320, upload-time = "2026-06-29T13:03:45.226Z" }, + { url = "https://files.pythonhosted.org/packages/c1/d6/5a59d938244a30735fe62d9433fd325f9021ea29d89780ea4596ea93bc89/jiter-0.16.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:8d031aabecc4f1b6276adfb42e3aabb77c89d468bf616600e8d3a11328929053", size = 350520, upload-time = "2026-06-29T13:03:46.671Z" }, + { url = "https://files.pythonhosted.org/packages/67/f8/c4a857f49c9af125f6bbcac7e3eee7f7978ed89682833062e2dbf62576b1/jiter-0.16.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eab2cd170150e70153de16896a1774e3a1dca80154c56b54d7a812c479a7165e", size = 387550, upload-time = "2026-06-29T13:03:48.361Z" }, + { url = "https://files.pythonhosted.org/packages/8b/d6/5fbc2f7d6b67b754caa61a993a2e626e815dec47ffc2f9e35f01adfebec7/jiter-0.16.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:6edb63a46e65a82c26800a868e49b2cac30dd5a4218b88d74bc2c848c8ad60bb", size = 515424, upload-time = "2026-06-29T13:03:49.881Z" }, + { url = "https://files.pythonhosted.org/packages/ed/54/284f0164b64a5fed915fea6ba7e9ba9b3d8d37c67d59cf2e3bb99d45cdfe/jiter-0.16.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:659039cc50b5addcc35fcc87ae2c1833b7c0a8e5326ef631a75e4478447bcf84", size = 546981, upload-time = "2026-06-29T13:03:51.363Z" }, + { url = "https://files.pythonhosted.org/packages/13/c5/2a467585a576594384e1d2c43e1224deaafc085f24e243529cf98beef8e1/jiter-0.16.0-cp313-cp313-win32.whl", hash = "sha256:c9c53be232c2e206ef9cdbad81a48bfa74c3d3f08bcf8124630a8a748aad993e", size = 202853, upload-time = "2026-06-29T13:03:53.015Z" }, + { url = "https://files.pythonhosted.org/packages/88/6a/de61d04b9eec69c71719968d2f716532a3bc121170c44a39e14979c6be81/jiter-0.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:baad945ed47f163ad833314f8e3288c396118934f94e7bbb9e243ce4b341a4fd", size = 196160, upload-time = "2026-06-29T13:03:54.447Z" }, + { url = "https://files.pythonhosted.org/packages/19/4b/b390ed59bafb3f31d008d1218578f10327714484b334439947f7e5b11e7f/jiter-0.16.0-cp313-cp313-win_arm64.whl", hash = "sha256:3c1fd2dbe1b0af19e987f03fe66c5f5bd105a2229c1aff4ab14890b24f41d21a", size = 189862, upload-time = "2026-06-29T13:03:55.754Z" }, + { url = "https://files.pythonhosted.org/packages/06/d3/8e278946d43eeca2585b4dd0834a887cd71136329b837f3a16ed86a8b4b0/jiter-0.16.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:850ccb1d7eedb4200f4014b1c0e8a577de114fc3cd88faad646dcc9bc4bb12ad", size = 304518, upload-time = "2026-06-29T13:05:00.172Z" }, + { url = "https://files.pythonhosted.org/packages/72/43/28d4ef495028bf0506a413d4db3f4eb3e7288a382e0f065f306a17bbeb5e/jiter-0.16.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:e34e97bda77eb63242a410243c071e28ac7e0d8c0948c5ee658498690a4b2f2f", size = 310207, upload-time = "2026-06-29T13:05:02.123Z" }, + { url = "https://files.pythonhosted.org/packages/e0/ca/c366b1012da1d640de975d9683acd44e4d150d9068845d0ca2610435253f/jiter-0.16.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7dc85ea77d4abbae8bad0d3538678aedee75bceec4e2f6c8dfb1c74772e5aa5", size = 342771, upload-time = "2026-06-29T13:05:03.55Z" }, + { url = "https://files.pythonhosted.org/packages/16/52/50cc4056fc1ae02e7154704e7ecc89df0afb8300222cfe8a52d3f67e4730/jiter-0.16.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17ca7fae79f6d99cd9a042b75f917eaada7b895cfc7dd2ee3a16089dcaec7a85", size = 346468, upload-time = "2026-06-29T13:05:05.452Z" }, + { url = "https://files.pythonhosted.org/packages/98/ab/664fd8c4be028b2bedd3d2ff08769c4ede23d0dbc87a77c62384a0515b5d/jiter-0.16.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:f17d61a28b4b3e0e3e2ba98490c70501403b4d196f78732439160e7fd3678127", size = 303106, upload-time = "2026-06-29T13:05:07.118Z" }, + { url = "https://files.pythonhosted.org/packages/1a/07/421f1d5b65493a76e16027b848aba6a7d28073ae75944fa4289cc914d39f/jiter-0.16.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:96e38eea538c8ddf853a35727c7be0741c76c13f04148ac5c116222f50ece3b3", size = 304658, upload-time = "2026-06-29T13:05:08.708Z" }, + { url = "https://files.pythonhosted.org/packages/0a/db/bba1155f01a01c3c37a89425d571da751bbedf5c54247b831a04cb971798/jiter-0.16.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d284fb8d94d5855d60c44fefcab4bf966f1da6fada73992b01f6f0c9bc0c6702", size = 339719, upload-time = "2026-06-29T13:05:10.41Z" }, + { url = "https://files.pythonhosted.org/packages/78/f7/18a1afcd64f35314b68c1f23afcd9994d0bc13e65cc77517afff4e83986d/jiter-0.16.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d613743df53199b1aa256a7d328340da6d7078aac7705a7db9d7a791e9cfd2", size = 343885, upload-time = "2026-06-29T13:05:12.087Z" }, +] + +[[package]] +name = "markdown" +version = "3.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805, upload-time = "2026-02-09T14:57:26.942Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + [[package]] name = "nemo-fabric-adapters-common" version = "0.1.0" @@ -13,13 +552,380 @@ version = "0.1.0" source = { editable = "." } dependencies = [ { name = "nemo-fabric-adapters-common" }, - { name = "pyyaml" }, +] + +[package.optional-dependencies] +full = [ + { name = "hermes-agent" }, + { name = "nemo-relay" }, +] +harness = [ + { name = "hermes-agent" }, +] +relay = [ + { name = "nemo-relay" }, ] [package.metadata] requires-dist = [ + { name = "hermes-agent", marker = "python_full_version < '3.14' and extra == 'full'", specifier = ">=0.17.0" }, + { name = "hermes-agent", marker = "python_full_version < '3.14' and extra == 'harness'", specifier = ">=0.17.0" }, { name = "nemo-fabric-adapters-common", editable = "../common" }, - { name = "pyyaml", specifier = ">=6.0" }, + { name = "nemo-relay", marker = "extra == 'full'", specifier = ">=0.6.0,<0.7" }, + { name = "nemo-relay", marker = "extra == 'relay'", specifier = ">=0.6.0,<0.7" }, +] +provides-extras = ["harness", "relay", "full"] + +[[package]] +name = "nemo-relay" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/65/d320016505457cc30971f575e8dadffb923b7cfc780ab8bb25a4ce9d305c/nemo_relay-0.6.0-cp311-abi3-macosx_11_0_arm64.whl", hash = "sha256:ad5dae6febf6532d7b113abc2a404679c8feffc499df3034b93d9a078185d2bb", size = 9917779, upload-time = "2026-07-22T20:07:48.961Z" }, + { url = "https://files.pythonhosted.org/packages/ae/c0/f33250e71c4206da1b339072893f9a1e39295fe1aceb9a2fef4b8620a0f2/nemo_relay-0.6.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0cd9570f64c6956fe3bfb82af1cdb3ee70cb50b51098cdb0de831c3f9b4e904", size = 8888375, upload-time = "2026-07-22T20:07:51.049Z" }, + { url = "https://files.pythonhosted.org/packages/a3/f4/d1dfaed022da0f6f14765a122867f976a69cc520fe1faaf99757f5719d1f/nemo_relay-0.6.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:849daa9e45158ac581e54506e0fcc7a24f557d1ed06dbdc074f5de7a00393cbc", size = 9336372, upload-time = "2026-07-22T20:07:53.224Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b0/908d77f75b9054e1e403da78f7d9430249a45939070d4298abbb41a04b5b/nemo_relay-0.6.0-cp311-abi3-win_amd64.whl", hash = "sha256:bfbbedfd130fa95c9b8c04643c30910df850e0ed3500beeab82b00ca2d94e7ea", size = 9613425, upload-time = "2026-07-22T20:07:55.175Z" }, + { url = "https://files.pythonhosted.org/packages/cd/71/c438b9d746303ff7f270d99f13b250bf947cdac3e52de2a83fd132cbca0b/nemo_relay-0.6.0-cp311-abi3-win_arm64.whl", hash = "sha256:82fe132943399d89e6ec34dc28df0be7bbe41b84f6698c545928b8816b6010f6", size = 9034810, upload-time = "2026-07-22T20:07:57.467Z" }, +] + +[[package]] +name = "openai" +version = "2.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/13/17e87641b89b74552ed408a92b231283786523edddc95f3545809fab673c/openai-2.24.0.tar.gz", hash = "sha256:1e5769f540dbd01cb33bc4716a23e67b9d695161a734aff9c5f925e2bf99a673", size = 658717, upload-time = "2026-02-24T20:02:07.958Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl", hash = "sha256:fed30480d7d6c884303287bde864980a4b137b60553ffbcf9ab4a233b7a73d94", size = 1120122, upload-time = "2026-02-24T20:02:05.669Z" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, +] + +[[package]] +name = "pathspec" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, +] + +[[package]] +name = "pillow" +version = "12.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/e1/748f5663efe6edcfc4e74b2b93edfb9b8b99b67f21a854c3ae416500a2d9/pillow-12.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:8be29e59487a79f173507c30ddf57e733a357f67881430449bb32614075a40ab", size = 5354347, upload-time = "2026-04-01T14:42:44.255Z" }, + { url = "https://files.pythonhosted.org/packages/47/a1/d5ff69e747374c33a3b53b9f98cca7889fce1fd03d79cdc4e1bccc6c5a87/pillow-12.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:71cde9a1e1551df7d34a25462fc60325e8a11a82cc2e2f54578e5e9a1e153d65", size = 4695873, upload-time = "2026-04-01T14:42:46.452Z" }, + { url = "https://files.pythonhosted.org/packages/df/21/e3fbdf54408a973c7f7f89a23b2cb97a7ef30c61ab4142af31eee6aebc88/pillow-12.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f490f9368b6fc026f021db16d7ec2fbf7d89e2edb42e8ec09d2c60505f5729c7", size = 6280168, upload-time = "2026-04-01T14:42:49.228Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f1/00b7278c7dd52b17ad4329153748f87b6756ec195ff786c2bdf12518337d/pillow-12.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8bd7903a5f2a4545f6fd5935c90058b89d30045568985a71c79f5fd6edf9b91e", size = 8088188, upload-time = "2026-04-01T14:42:51.735Z" }, + { url = "https://files.pythonhosted.org/packages/ad/cf/220a5994ef1b10e70e85748b75649d77d506499352be135a4989c957b701/pillow-12.2.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3997232e10d2920a68d25191392e3a4487d8183039e1c74c2297f00ed1c50705", size = 6394401, upload-time = "2026-04-01T14:42:54.343Z" }, + { url = "https://files.pythonhosted.org/packages/e9/bd/e51a61b1054f09437acfbc2ff9106c30d1eb76bc1453d428399946781253/pillow-12.2.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e74473c875d78b8e9d5da2a70f7099549f9eb37ded4e2f6a463e60125bccd176", size = 7079655, upload-time = "2026-04-01T14:42:56.954Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3d/45132c57d5fb4b5744567c3817026480ac7fc3ce5d4c47902bc0e7f6f853/pillow-12.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:56a3f9c60a13133a98ecff6197af34d7824de9b7b38c3654861a725c970c197b", size = 6503105, upload-time = "2026-04-01T14:42:59.847Z" }, + { url = "https://files.pythonhosted.org/packages/7d/2e/9df2fc1e82097b1df3dce58dc43286aa01068e918c07574711fcc53e6fb4/pillow-12.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90e6f81de50ad6b534cab6e5aef77ff6e37722b2f5d908686f4a5c9eba17a909", size = 7203402, upload-time = "2026-04-01T14:43:02.664Z" }, + { url = "https://files.pythonhosted.org/packages/bd/2e/2941e42858ebb67e50ae741473de81c2984e6eff7b397017623c676e2e8d/pillow-12.2.0-cp311-cp311-win32.whl", hash = "sha256:8c984051042858021a54926eb597d6ee3012393ce9c181814115df4c60b9a808", size = 6378149, upload-time = "2026-04-01T14:43:05.274Z" }, + { url = "https://files.pythonhosted.org/packages/69/42/836b6f3cd7f3e5fa10a1f1a5420447c17966044c8fbf589cc0452d5502db/pillow-12.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e6b2a0c538fc200b38ff9eb6628228b77908c319a005815f2dde585a0664b60", size = 7082626, upload-time = "2026-04-01T14:43:08.557Z" }, + { url = "https://files.pythonhosted.org/packages/c2/88/549194b5d6f1f494b485e493edc6693c0a16f4ada488e5bd974ed1f42fad/pillow-12.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:9a8a34cc89c67a65ea7437ce257cea81a9dad65b29805f3ecee8c8fe8ff25ffe", size = 2463531, upload-time = "2026-04-01T14:43:10.743Z" }, + { url = "https://files.pythonhosted.org/packages/58/be/7482c8a5ebebbc6470b3eb791812fff7d5e0216c2be3827b30b8bb6603ed/pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5", size = 5308279, upload-time = "2026-04-01T14:43:13.246Z" }, + { url = "https://files.pythonhosted.org/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421", size = 4695490, upload-time = "2026-04-01T14:43:15.584Z" }, + { url = "https://files.pythonhosted.org/packages/de/af/4e8e6869cbed569d43c416fad3dc4ecb944cb5d9492defaed89ddd6fe871/pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987", size = 6284462, upload-time = "2026-04-01T14:43:18.268Z" }, + { url = "https://files.pythonhosted.org/packages/e9/9e/c05e19657fd57841e476be1ab46c4d501bffbadbafdc31a6d665f8b737b6/pillow-12.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76", size = 8094744, upload-time = "2026-04-01T14:43:20.716Z" }, + { url = "https://files.pythonhosted.org/packages/2b/54/1789c455ed10176066b6e7e6da1b01e50e36f94ba584dc68d9eebfe9156d/pillow-12.2.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005", size = 6398371, upload-time = "2026-04-01T14:43:23.443Z" }, + { url = "https://files.pythonhosted.org/packages/43/e3/fdc657359e919462369869f1c9f0e973f353f9a9ee295a39b1fea8ee1a77/pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780", size = 7087215, upload-time = "2026-04-01T14:43:26.758Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f8/2f6825e441d5b1959d2ca5adec984210f1ec086435b0ed5f52c19b3b8a6e/pillow-12.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5", size = 6509783, upload-time = "2026-04-01T14:43:29.56Z" }, + { url = "https://files.pythonhosted.org/packages/67/f9/029a27095ad20f854f9dba026b3ea6428548316e057e6fc3545409e86651/pillow-12.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5", size = 7212112, upload-time = "2026-04-01T14:43:32.091Z" }, + { url = "https://files.pythonhosted.org/packages/be/42/025cfe05d1be22dbfdb4f264fe9de1ccda83f66e4fc3aac94748e784af04/pillow-12.2.0-cp312-cp312-win32.whl", hash = "sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940", size = 6378489, upload-time = "2026-04-01T14:43:34.601Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7b/25a221d2c761c6a8ae21bfa3874988ff2583e19cf8a27bf2fee358df7942/pillow-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5", size = 7084129, upload-time = "2026-04-01T14:43:37.213Z" }, + { url = "https://files.pythonhosted.org/packages/10/e1/542a474affab20fd4a0f1836cb234e8493519da6b76899e30bcc5d990b8b/pillow-12.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414", size = 2463612, upload-time = "2026-04-01T14:43:39.421Z" }, + { url = "https://files.pythonhosted.org/packages/4a/01/53d10cf0dbad820a8db274d259a37ba50b88b24768ddccec07355382d5ad/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8297651f5b5679c19968abefd6bb84d95fe30ef712eb1b2d9b2d31ca61267f4c", size = 4100837, upload-time = "2026-04-01T14:43:41.506Z" }, + { url = "https://files.pythonhosted.org/packages/0f/98/f3a6657ecb698c937f6c76ee564882945f29b79bad496abcba0e84659ec5/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:50d8520da2a6ce0af445fa6d648c4273c3eeefbc32d7ce049f22e8b5c3daecc2", size = 4176528, upload-time = "2026-04-01T14:43:43.773Z" }, + { url = "https://files.pythonhosted.org/packages/69/bc/8986948f05e3ea490b8442ea1c1d4d990b24a7e43d8a51b2c7d8b1dced36/pillow-12.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:766cef22385fa1091258ad7e6216792b156dc16d8d3fa607e7545b2b72061f1c", size = 3640401, upload-time = "2026-04-01T14:43:45.87Z" }, + { url = "https://files.pythonhosted.org/packages/34/46/6c717baadcd62bc8ed51d238d521ab651eaa74838291bda1f86fe1f864c9/pillow-12.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d2fd0fa6b5d9d1de415060363433f28da8b1526c1c129020435e186794b3795", size = 5308094, upload-time = "2026-04-01T14:43:48.438Z" }, + { url = "https://files.pythonhosted.org/packages/71/43/905a14a8b17fdb1ccb58d282454490662d2cb89a6bfec26af6d3520da5ec/pillow-12.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b25336f502b6ed02e889f4ece894a72612fe885889a6e8c4c80239ff6e5f5f", size = 4695402, upload-time = "2026-04-01T14:43:51.292Z" }, + { url = "https://files.pythonhosted.org/packages/73/dd/42107efcb777b16fa0393317eac58f5b5cf30e8392e266e76e51cff28c3d/pillow-12.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f1c943e96e85df3d3478f7b691f229887e143f81fedab9b20205349ab04d73ed", size = 6280005, upload-time = "2026-04-01T14:43:54.242Z" }, + { url = "https://files.pythonhosted.org/packages/a8/68/b93e09e5e8549019e61acf49f65b1a8530765a7f812c77a7461bca7e4494/pillow-12.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03f6fab9219220f041c74aeaa2939ff0062bd5c364ba9ce037197f4c6d498cd9", size = 8090669, upload-time = "2026-04-01T14:43:57.335Z" }, + { url = "https://files.pythonhosted.org/packages/4b/6e/3ccb54ce8ec4ddd1accd2d89004308b7b0b21c4ac3d20fa70af4760a4330/pillow-12.2.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdfebd752ec52bf5bb4e35d9c64b40826bc5b40a13df7c3cda20a2c03a0f5ed", size = 6395194, upload-time = "2026-04-01T14:43:59.864Z" }, + { url = "https://files.pythonhosted.org/packages/67/ee/21d4e8536afd1a328f01b359b4d3997b291ffd35a237c877b331c1c3b71c/pillow-12.2.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eedf4b74eda2b5a4b2b2fb4c006d6295df3bf29e459e198c90ea48e130dc75c3", size = 7082423, upload-time = "2026-04-01T14:44:02.74Z" }, + { url = "https://files.pythonhosted.org/packages/78/5f/e9f86ab0146464e8c133fe85df987ed9e77e08b29d8d35f9f9f4d6f917ba/pillow-12.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:00a2865911330191c0b818c59103b58a5e697cae67042366970a6b6f1b20b7f9", size = 6505667, upload-time = "2026-04-01T14:44:05.381Z" }, + { url = "https://files.pythonhosted.org/packages/ed/1e/409007f56a2fdce61584fd3acbc2bbc259857d555196cedcadc68c015c82/pillow-12.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e1757442ed87f4912397c6d35a0db6a7b52592156014706f17658ff58bbf795", size = 7208580, upload-time = "2026-04-01T14:44:08.39Z" }, + { url = "https://files.pythonhosted.org/packages/23/c4/7349421080b12fb35414607b8871e9534546c128a11965fd4a7002ccfbee/pillow-12.2.0-cp313-cp313-win32.whl", hash = "sha256:144748b3af2d1b358d41286056d0003f47cb339b8c43a9ea42f5fea4d8c66b6e", size = 6375896, upload-time = "2026-04-01T14:44:11.197Z" }, + { url = "https://files.pythonhosted.org/packages/3f/82/8a3739a5e470b3c6cbb1d21d315800d8e16bff503d1f16b03a4ec3212786/pillow-12.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:390ede346628ccc626e5730107cde16c42d3836b89662a115a921f28440e6a3b", size = 7081266, upload-time = "2026-04-01T14:44:13.947Z" }, + { url = "https://files.pythonhosted.org/packages/c3/25/f968f618a062574294592f668218f8af564830ccebdd1fa6200f598e65c5/pillow-12.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:8023abc91fba39036dbce14a7d6535632f99c0b857807cbbbf21ecc9f4717f06", size = 2463508, upload-time = "2026-04-01T14:44:16.312Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a4/b342930964e3cb4dce5038ae34b0eab4653334995336cd486c5a8c25a00c/pillow-12.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:042db20a421b9bafecc4b84a8b6e444686bd9d836c7fd24542db3e7df7baad9b", size = 5309927, upload-time = "2026-04-01T14:44:18.89Z" }, + { url = "https://files.pythonhosted.org/packages/9f/de/23198e0a65a9cf06123f5435a5d95cea62a635697f8f03d134d3f3a96151/pillow-12.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd025009355c926a84a612fecf58bb315a3f6814b17ead51a8e48d3823d9087f", size = 4698624, upload-time = "2026-04-01T14:44:21.115Z" }, + { url = "https://files.pythonhosted.org/packages/01/a6/1265e977f17d93ea37aa28aa81bad4fa597933879fac2520d24e021c8da3/pillow-12.2.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88ddbc66737e277852913bd1e07c150cc7bb124539f94c4e2df5344494e0a612", size = 6321252, upload-time = "2026-04-01T14:44:23.663Z" }, + { url = "https://files.pythonhosted.org/packages/3c/83/5982eb4a285967baa70340320be9f88e57665a387e3a53a7f0db8231a0cd/pillow-12.2.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d362d1878f00c142b7e1a16e6e5e780f02be8195123f164edf7eddd911eefe7c", size = 8126550, upload-time = "2026-04-01T14:44:26.772Z" }, + { url = "https://files.pythonhosted.org/packages/4e/48/6ffc514adce69f6050d0753b1a18fd920fce8cac87620d5a31231b04bfc5/pillow-12.2.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c727a6d53cb0018aadd8018c2b938376af27914a68a492f59dfcaca650d5eea", size = 6433114, upload-time = "2026-04-01T14:44:29.615Z" }, + { url = "https://files.pythonhosted.org/packages/36/a3/f9a77144231fb8d40ee27107b4463e205fa4677e2ca2548e14da5cf18dce/pillow-12.2.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:efd8c21c98c5cc60653bcb311bef2ce0401642b7ce9d09e03a7da87c878289d4", size = 7115667, upload-time = "2026-04-01T14:44:32.773Z" }, + { url = "https://files.pythonhosted.org/packages/c1/fc/ac4ee3041e7d5a565e1c4fd72a113f03b6394cc72ab7089d27608f8aaccb/pillow-12.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f08483a632889536b8139663db60f6724bfcb443c96f1b18855860d7d5c0fd4", size = 6538966, upload-time = "2026-04-01T14:44:35.252Z" }, + { url = "https://files.pythonhosted.org/packages/c0/a8/27fb307055087f3668f6d0a8ccb636e7431d56ed0750e07a60547b1e083e/pillow-12.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dac8d77255a37e81a2efcbd1fc05f1c15ee82200e6c240d7e127e25e365c39ea", size = 7238241, upload-time = "2026-04-01T14:44:37.875Z" }, + { url = "https://files.pythonhosted.org/packages/ad/4b/926ab182c07fccae9fcb120043464e1ff1564775ec8864f21a0ebce6ac25/pillow-12.2.0-cp313-cp313t-win32.whl", hash = "sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24", size = 6379592, upload-time = "2026-04-01T14:44:40.336Z" }, + { url = "https://files.pythonhosted.org/packages/c2/c4/f9e476451a098181b30050cc4c9a3556b64c02cf6497ea421ac047e89e4b/pillow-12.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98", size = 7085542, upload-time = "2026-04-01T14:44:43.251Z" }, + { url = "https://files.pythonhosted.org/packages/00/a4/285f12aeacbe2d6dc36c407dfbbe9e96d4a80b0fb710a337f6d2ad978c75/pillow-12.2.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453", size = 2465765, upload-time = "2026-04-01T14:44:45.996Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b7/2437044fb910f499610356d1352e3423753c98e34f915252aafecc64889f/pillow-12.2.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538bd5e05efec03ae613fd89c4ce0368ecd2ba239cc25b9f9be7ed426b0af1f", size = 5273969, upload-time = "2026-04-01T14:45:55.538Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f4/8316e31de11b780f4ac08ef3654a75555e624a98db1056ecb2122d008d5a/pillow-12.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:394167b21da716608eac917c60aa9b969421b5dcbbe02ae7f013e7b85811c69d", size = 4659674, upload-time = "2026-04-01T14:45:58.093Z" }, + { url = "https://files.pythonhosted.org/packages/d4/37/664fca7201f8bb2aa1d20e2c3d5564a62e6ae5111741966c8319ca802361/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5d04bfa02cc2d23b497d1e90a0f927070043f6cbf303e738300532379a4b4e0f", size = 5288479, upload-time = "2026-04-01T14:46:01.141Z" }, + { url = "https://files.pythonhosted.org/packages/49/62/5b0ed78fce87346be7a5cfcfaaad91f6a1f98c26f86bdbafa2066c647ef6/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0c838a5125cee37e68edec915651521191cef1e6aa336b855f495766e77a366e", size = 7032230, upload-time = "2026-04-01T14:46:03.874Z" }, + { url = "https://files.pythonhosted.org/packages/c3/28/ec0fc38107fc32536908034e990c47914c57cd7c5a3ece4d8d8f7ffd7e27/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a6c9fa44005fa37a91ebfc95d081e8079757d2e904b27103f4f5fa6f0bf78c0", size = 5355404, upload-time = "2026-04-01T14:46:06.33Z" }, + { url = "https://files.pythonhosted.org/packages/5e/8b/51b0eddcfa2180d60e41f06bd6d0a62202b20b59c68f5a132e615b75aecf/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:25373b66e0dd5905ed63fa3cae13c82fbddf3079f2c8bf15c6fb6a35586324c1", size = 6002215, upload-time = "2026-04-01T14:46:08.83Z" }, + { url = "https://files.pythonhosted.org/packages/bc/60/5382c03e1970de634027cee8e1b7d39776b778b81812aaf45b694dfe9e28/pillow-12.2.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bfa9c230d2fe991bed5318a5f119bd6780cda2915cca595393649fc118ab895e", size = 7080946, upload-time = "2026-04-01T14:46:11.734Z" }, +] + +[[package]] +name = "portalocker" +version = "3.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywin32", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/77/65b857a69ed876e1951e88aaba60f5ce6120c33703f7cb61a3c894b8c1b6/portalocker-3.2.0.tar.gz", hash = "sha256:1f3002956a54a8c3730586c5c77bf18fae4149e07eaf1c29fc3faf4d5a3f89ac", size = 95644, upload-time = "2025-06-14T13:20:40.03Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/a6/38c8e2f318bf67d338f4d629e93b0b4b9af331f455f0390ea8ce4a099b26/portalocker-3.2.0-py3-none-any.whl", hash = "sha256:3cdc5f565312224bc570c49337bd21428bba0ef363bbcf58b9ef4a9f11779968", size = 22424, upload-time = "2025-06-14T13:20:38.083Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, +] + +[[package]] +name = "psutil" +version = "7.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/08/510cbdb69c25a96f4ae523f733cdc963ae654904e8db864c07585ef99875/psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b", size = 130595, upload-time = "2026-01-28T18:14:57.293Z" }, + { url = "https://files.pythonhosted.org/packages/d6/f5/97baea3fe7a5a9af7436301f85490905379b1c6f2dd51fe3ecf24b4c5fbf/psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea", size = 131082, upload-time = "2026-01-28T18:14:59.732Z" }, + { url = "https://files.pythonhosted.org/packages/37/d6/246513fbf9fa174af531f28412297dd05241d97a75911ac8febefa1a53c6/psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63", size = 181476, upload-time = "2026-01-28T18:15:01.884Z" }, + { url = "https://files.pythonhosted.org/packages/b8/b5/9182c9af3836cca61696dabe4fd1304e17bc56cb62f17439e1154f225dd3/psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312", size = 184062, upload-time = "2026-01-28T18:15:04.436Z" }, + { url = "https://files.pythonhosted.org/packages/16/ba/0756dca669f5a9300d0cbcbfae9a4c30e446dfc7440ffe43ded5724bfd93/psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b", size = 139893, upload-time = "2026-01-28T18:15:06.378Z" }, + { url = "https://files.pythonhosted.org/packages/1c/61/8fa0e26f33623b49949346de05ec1ddaad02ed8ba64af45f40a147dbfa97/psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9", size = 135589, upload-time = "2026-01-28T18:15:08.03Z" }, + { url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" }, + { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" }, + { url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" }, + { url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" }, + { url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" }, + { url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" }, + { url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" }, + { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + +[[package]] +name = "pydantic" +version = "2.13.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.46.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/fa/6d7708d2cfc1a832acb6aeb0cd16e801902df8a0f583bb3b4b527fde022e/pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594", size = 2111872, upload-time = "2026-05-06T13:40:27.596Z" }, + { url = "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c", size = 1948255, upload-time = "2026-05-06T13:39:12.574Z" }, + { url = "https://files.pythonhosted.org/packages/43/3a/41114a9f7569b84b4d84e7a018c57c56347dac30c0d4a872946ec4e36c46/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826", size = 1972827, upload-time = "2026-05-06T13:38:19.841Z" }, + { url = "https://files.pythonhosted.org/packages/ef/25/1ab42e8048fe551934d9884e8d64daa7e990ad386f310a15981aeb6a5b08/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04", size = 2041051, upload-time = "2026-05-06T13:38:10.447Z" }, + { url = "https://files.pythonhosted.org/packages/94/c2/1a934597ddf08da410385b3b7aae91956a5a76c635effef456074fad7e88/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e", size = 2221314, upload-time = "2026-05-06T13:40:13.089Z" }, + { url = "https://files.pythonhosted.org/packages/02/6d/9e8ad178c9c4df27ad3c8f25d1fe2a7ab0d2ba0559fad4aee5d3d1f16771/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3", size = 2285146, upload-time = "2026-05-06T13:38:59.224Z" }, + { url = "https://files.pythonhosted.org/packages/80/50/540cd3aeefc041beb111125c4bff779831a2111fc6b15a9138cda277d32c/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4", size = 2089685, upload-time = "2026-05-06T13:38:17.762Z" }, + { url = "https://files.pythonhosted.org/packages/6b/a4/b440ad35f05f6a38f89fa0f149accb3f0e02be94ca5e15f3c449a61b4bc9/pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398", size = 2115420, upload-time = "2026-05-06T13:37:58.195Z" }, + { url = "https://files.pythonhosted.org/packages/99/61/de4f55db8dfd57bfdfa9a12ec90fe1b57c4f41062f7ca86f08586b3e0ac0/pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3", size = 2165122, upload-time = "2026-05-06T13:37:01.167Z" }, + { url = "https://files.pythonhosted.org/packages/f7/52/7c529d7bdb2d1068bd52f51fe32572c8301f9a4febf1948f10639f1436f5/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848", size = 2182573, upload-time = "2026-05-06T13:38:45.04Z" }, + { url = "https://files.pythonhosted.org/packages/37/b3/7c40325848ba78247f2812dcf9c7274e38cd801820ca6dd9fe63bcfb0eb4/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3", size = 2317139, upload-time = "2026-05-06T13:37:15.539Z" }, + { url = "https://files.pythonhosted.org/packages/d9/37/f913f81a657c865b75da6c0dbed79876073c2a43b5bd9edbe8da785e4d49/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109", size = 2360433, upload-time = "2026-05-06T13:37:30.099Z" }, + { url = "https://files.pythonhosted.org/packages/c4/67/6acaa1be2567f9256b056d8477158cac7240813956ce86e49deae8e173b4/pydantic_core-2.46.4-cp311-cp311-win32.whl", hash = "sha256:041bde0a48fd37cf71cab1c9d56d3e8625a3793fef1f7dd232b3ff37e978ecda", size = 1985513, upload-time = "2026-05-06T13:38:15.669Z" }, + { url = "https://files.pythonhosted.org/packages/aa/e6/c505f83dfeda9a2e5c995cfd872949e4d05e12f7feb3dca72f633daefa94/pydantic_core-2.46.4-cp311-cp311-win_amd64.whl", hash = "sha256:6f2eeda33a839975441c86a4119e1383c50b47faf0cbb5176985565c6bb02c33", size = 2071114, upload-time = "2026-05-06T13:40:35.416Z" }, + { url = "https://files.pythonhosted.org/packages/0f/da/7a263a96d965d9d0df5e8de8a475f33495451117035b09acb110288c381f/pydantic_core-2.46.4-cp311-cp311-win_arm64.whl", hash = "sha256:14f4c5d6db102bd796a627bbb3a17b4cf4574b9ae861d8b7c9a9661c6dd3362d", size = 2044298, upload-time = "2026-05-06T13:38:29.754Z" }, + { url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158, upload-time = "2026-05-06T13:38:57.215Z" }, + { url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724, upload-time = "2026-05-06T13:37:02.697Z" }, + { url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742, upload-time = "2026-05-06T13:37:09.448Z" }, + { url = "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", size = 2052418, upload-time = "2026-05-06T13:37:38.234Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", size = 2232274, upload-time = "2026-05-06T13:38:27.753Z" }, + { url = "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", size = 2309940, upload-time = "2026-05-06T13:38:05.353Z" }, + { url = "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", size = 2094516, upload-time = "2026-05-06T13:39:10.577Z" }, + { url = "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", size = 2136854, upload-time = "2026-05-06T13:40:22.59Z" }, + { url = "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", size = 2180306, upload-time = "2026-05-06T13:40:10.666Z" }, + { url = "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", size = 2190044, upload-time = "2026-05-06T13:40:43.231Z" }, + { url = "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", size = 2329133, upload-time = "2026-05-06T13:39:57.365Z" }, + { url = "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", size = 2374464, upload-time = "2026-05-06T13:38:06.976Z" }, + { url = "https://files.pythonhosted.org/packages/47/bd/6f2fc8188f31bf10590f1e98e7b306336161fac930a8c514cd7bd828c7dc/pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894", size = 1974823, upload-time = "2026-05-06T13:40:47.985Z" }, + { url = "https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89", size = 2072919, upload-time = "2026-05-06T13:39:21.153Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ba/f463d006e0c47373ca7ec5e1a261c59dc01ef4d62b2657af925fb0deee3a/pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a", size = 2027604, upload-time = "2026-05-06T13:39:03.753Z" }, + { url = "https://files.pythonhosted.org/packages/51/a2/5d30b469c5267a17b39dec53208222f76a8d351dfac4af661888c5aee77d/pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008", size = 2106306, upload-time = "2026-05-06T13:37:48.029Z" }, + { url = "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4", size = 1951906, upload-time = "2026-05-06T13:37:17.012Z" }, + { url = "https://files.pythonhosted.org/packages/03/d5/fd02da45b659668b05923b17ba3a0100a0a3d5541e3bd8fcc4ecb711309e/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76", size = 1976802, upload-time = "2026-05-06T13:37:35.113Z" }, + { url = "https://files.pythonhosted.org/packages/21/f2/95727e1368be3d3ed485eaab7adbd7dda408f33f7a36e8b48e0144002b91/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3", size = 2052446, upload-time = "2026-05-06T13:37:12.313Z" }, + { url = "https://files.pythonhosted.org/packages/9c/86/5d99feea3f77c7234b8718075b23db11532773c1a0dbd9b9490215dc2eeb/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76", size = 2232757, upload-time = "2026-05-06T13:39:01.149Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3a/508ac615935ef7588cf6d9e9b91309fdc2da751af865e02a9098de88258c/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4", size = 2309275, upload-time = "2026-05-06T13:37:41.406Z" }, + { url = "https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a", size = 2094467, upload-time = "2026-05-06T13:39:18.847Z" }, + { url = "https://files.pythonhosted.org/packages/2c/e2/f35033184cb11d0052daf4416e8e10a502ea2ac006fc4f459aee872727d1/pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262", size = 2134417, upload-time = "2026-05-06T13:40:17.944Z" }, + { url = "https://files.pythonhosted.org/packages/7e/7b/6ceeb1cc90e193862f444ebe373d8fdf613f0a82572dde03fb10734c6c71/pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e", size = 2179782, upload-time = "2026-05-06T13:40:32.618Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f2/c8d7773ede6af08036423a00ae0ceffce266c3c52a096c435d68c896083f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd", size = 2188782, upload-time = "2026-05-06T13:36:51.018Z" }, + { url = "https://files.pythonhosted.org/packages/59/31/0c864784e31f09f05cdd87606f08923b9c9e7f6e51dd27f20f62f975ce9f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be", size = 2328334, upload-time = "2026-05-06T13:40:37.764Z" }, + { url = "https://files.pythonhosted.org/packages/c2/eb/4f6c8a41efa30baa755590f4141abf3a8c370fab610915733e74134a7270/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d", size = 2372986, upload-time = "2026-05-06T13:39:34.152Z" }, + { url = "https://files.pythonhosted.org/packages/5b/24/b375a480d53113860c299764bfe9f349a3dc9108b3adc0d7f0d786492ebf/pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb", size = 1973693, upload-time = "2026-05-06T13:37:55.072Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e8/cff247591966f2d22ec8c003cd7587e27b7ba7b81ab2fb888e3ab75dc285/pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292", size = 2071819, upload-time = "2026-05-06T13:38:49.139Z" }, + { url = "https://files.pythonhosted.org/packages/c6/1a/f4aee670d5670e9e148e0c82c7db98d780be566c6e6a97ee8035528ca0b3/pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d", size = 2027411, upload-time = "2026-05-06T13:40:45.796Z" }, + { url = "https://files.pythonhosted.org/packages/ee/a4/73995fd4ebbb46ba0ee51e6fa049b8f02c40daebb762208feda8a6b7894d/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:14d4edf427bdcf950a8a02d7cb44a08614388dd6e1bdcbf4f67504fa7887da9c", size = 2111589, upload-time = "2026-05-06T13:37:10.817Z" }, + { url = "https://files.pythonhosted.org/packages/fb/7f/f37d3a5e8bfcc2e403f5c57a730f2d815693fb42119e8ea48b3789335af1/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0ce40cd7b21210e99342afafbd4d0f76d784eb5b1d60f3bdc566be4983c6c73b", size = 1944552, upload-time = "2026-05-06T13:36:56.717Z" }, + { url = "https://files.pythonhosted.org/packages/15/3c/d7eb777b3ff43e8433a4efb39a17aa8fd98a4ee8561a24a67ef5db07b2d6/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90884113d8b48f760e9587002789ddd741e76ab9f89518cd1e43b1f1a52ec44b", size = 1982984, upload-time = "2026-05-06T13:39:06.207Z" }, + { url = "https://files.pythonhosted.org/packages/63/87/70b9f40170a81afd55ca26c9b2acb25c20d64bcfbf888fafecb3ba077d4c/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ce7632c22d837c95301830e111ad0128a32b8207533b60896a96c4915192ea", size = 2138417, upload-time = "2026-05-06T13:39:45.476Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527, upload-time = "2026-05-06T13:39:52.283Z" }, + { url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024, upload-time = "2026-05-06T13:40:15.671Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696, upload-time = "2026-05-06T13:38:34.717Z" }, + { url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590, upload-time = "2026-05-06T13:39:29.883Z" }, + { url = "https://files.pythonhosted.org/packages/11/cb/428de0385b6c8d44b716feba566abfacfbd23ee3c4439faa789a1456242f/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0", size = 2112782, upload-time = "2026-05-06T13:37:04.016Z" }, + { url = "https://files.pythonhosted.org/packages/0b/b5/6a17bdadd0fc1f170adfd05a20d37c832f52b117b4d9131da1f41bb097ce/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7", size = 1952146, upload-time = "2026-05-06T13:39:43.092Z" }, + { url = "https://files.pythonhosted.org/packages/2a/dc/03734d80e362cd43ef65428e9de77c730ce7f2f11c60d2b1e1b39f0fbf99/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2", size = 2134492, upload-time = "2026-05-06T13:36:58.124Z" }, + { url = "https://files.pythonhosted.org/packages/de/df/5e5ffc085ed07cc22d298134d3d911c63e91f6a0eb91fe646750a3209910/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9", size = 2156604, upload-time = "2026-05-06T13:37:49.88Z" }, + { url = "https://files.pythonhosted.org/packages/81/44/6e112a4253e56f5705467cbab7ab5e91ee7398ba3d56d358635958893d3e/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf", size = 2183828, upload-time = "2026-05-06T13:37:43.053Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ad/5565071e937d8e752842ac241463944c9eb14c87e2d269f2658a5bd05e98/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30", size = 2310000, upload-time = "2026-05-06T13:37:56.694Z" }, + { url = "https://files.pythonhosted.org/packages/4f/c3/66883a5cec183e7fba4d024b4cbbe61851a63750ef606b0afecc46d1f2bf/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc", size = 2361286, upload-time = "2026-05-06T13:40:05.667Z" }, + { url = "https://files.pythonhosted.org/packages/4b/2d/69abac8f838090bbecd5df894befb2c2619e7996a98ddb949db9f3b93225/pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983", size = 2193071, upload-time = "2026-05-06T13:38:08.682Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pyjwt" +version = "2.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/81/58d0ac84e1ef3a3843791d6954d94c0b33d526c75eeb1efbce9d0a4c4077/pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423", size = 107515, upload-time = "2026-05-21T19:54:36.618Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728", size = 31274, upload-time = "2026-05-21T19:54:35.362Z" }, +] + +[package.optional-dependencies] +crypto = [ + { name = "cryptography" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, +] + +[[package]] +name = "python-multipart" +version = "0.0.32" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/42/55c32bb9b12693c092ad250a0e82edb5b31ddeda6eb772de5f308b3804ad/python_multipart-0.0.32.tar.gz", hash = "sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e", size = 46881, upload-time = "2026-06-04T16:18:58.647Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl", hash = "sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23", size = 30042, upload-time = "2026-06-04T16:18:57.319Z" }, +] + +[[package]] +name = "pytz" +version = "2026.3.post1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/48/fb042503b6ca6cd271261dc559fd6432f7d8c713153e9ec5c591af4dfc1c/pytz-2026.3.post1.tar.gz", hash = "sha256:2211d3fcf9a797d3405cac96ac7f61d80e6a644f72a3309607282fe8a2010c5d", size = 319745, upload-time = "2026-07-25T15:12:07.385Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl", hash = "sha256:dd95840dd199baea12d9cc096a1d452caa6596a1c1e4b5f3dbd1541855d5e815", size = 508283, upload-time = "2026-07-25T15:12:05.782Z" }, +] + +[[package]] +name = "pywin32" +version = "312" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/f5/10a6e845a00fc5e7afd0a988b744f403d4d57162a28d160a093c4d9322f0/pywin32-312-cp311-cp311-win32.whl", hash = "sha256:17948aeadbdb091f0ced6ef0841620794e68327b94ee415571c1203594b7215c", size = 6362659, upload-time = "2026-06-04T07:49:21.349Z" }, + { url = "https://files.pythonhosted.org/packages/35/c4/dcd2d62b5944b6d5db53413a5899016ccd57ffcb7278f3f81655d25d2027/pywin32-312-cp311-cp311-win_amd64.whl", hash = "sha256:d11417d84412f859b722fad0841b3614459ed0047f7542d8362e77884f6b6e8a", size = 6928825, upload-time = "2026-06-04T07:49:23.934Z" }, + { url = "https://files.pythonhosted.org/packages/b7/56/3cbb433fe4501cdba2eb9040f56a4e1a8243faa4186b25295564d1a7a79d/pywin32-312-cp311-cp311-win_arm64.whl", hash = "sha256:b2200a054ca6d6625c4842fc56a4976a4b47f96b73dbe5538c3f813a80359f47", size = 6721875, upload-time = "2026-06-04T07:49:26.416Z" }, + { url = "https://files.pythonhosted.org/packages/83/ff/32aa7d2ed0ab12b323aaa64f9b75e6ad4f8fd09f9ccfc28c79414d46838d/pywin32-312-cp312-cp312-win32.whl", hash = "sha256:dab4f65ac9c4e48400a2a0530c46c3c579cd5905ecd11b80692373915269208b", size = 6371877, upload-time = "2026-06-04T07:49:28.836Z" }, + { url = "https://files.pythonhosted.org/packages/03/d9/77040d3b43df3f3be32ea289433d660d2727f5ba327bc73be835127d9d60/pywin32-312-cp312-cp312-win_amd64.whl", hash = "sha256:b457f6d628a47e8a7346ce22acb7e1a46a4a78b52e1d17e1af56871bd19a93bc", size = 6914841, upload-time = "2026-06-04T07:49:31.85Z" }, + { url = "https://files.pythonhosted.org/packages/e3/cc/7b1ec671775756020a0ee7f4feeaf3c568f0ab86bd3900088cf986937a92/pywin32-312-cp312-cp312-win_arm64.whl", hash = "sha256:6017c58e12f6809fbb0555b75df144c2922a9ffd18e4b9b5afa863b6c1a9d950", size = 6727901, upload-time = "2026-06-04T07:49:34.244Z" }, + { url = "https://files.pythonhosted.org/packages/2d/41/12fbfd7f36ed2146d8bc9de96c2741296bf0d490b98508496cff322e274c/pywin32-312-cp313-cp313-win32.whl", hash = "sha256:7a27df850933d16a8eabfbaeb73d52b273e2da667f80d70b01a89d1f6828d02c", size = 6370184, upload-time = "2026-06-04T07:49:36.253Z" }, + { url = "https://files.pythonhosted.org/packages/ba/db/36a78e3403099d31d9746d13fdcde5accc43c1155f375a34d15983a479a7/pywin32-312-cp313-cp313-win_amd64.whl", hash = "sha256:c53e878d15a1c44788082bfe712a905433473aa38f86375b7cf8b45e3acbaaf9", size = 6914298, upload-time = "2026-06-04T07:49:38.876Z" }, + { url = "https://files.pythonhosted.org/packages/84/37/c1697194092b76de9ed47ca124323f02c57ffc8a45c06f88a3d5acaf01eb/pywin32-312-cp313-cp313-win_arm64.whl", hash = "sha256:59aba5d5940842075343a5ddc6b11f1cdf0d1567fe745290359dfbcc7c2eb831", size = 6727640, upload-time = "2026-06-04T07:49:41.083Z" }, +] + +[[package]] +name = "pywinpty" +version = "2.0.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/7c/917f9c4681bb8d34bfbe0b79d36bbcd902651aeab48790df3d30ba0202fb/pywinpty-2.0.15.tar.gz", hash = "sha256:312cf39153a8736c617d45ce8b6ad6cd2107de121df91c455b10ce6bba7a39b2", size = 29017, upload-time = "2025-02-03T21:53:23.265Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5e/ac/6884dcb7108af66ad53f73ef4dad096e768c9203a6e6ce5e6b0c4a46e238/pywinpty-2.0.15-cp311-cp311-win_amd64.whl", hash = "sha256:9a6bcec2df2707aaa9d08b86071970ee32c5026e10bcc3cc5f6f391d85baf7ca", size = 1405249, upload-time = "2025-02-03T21:55:47.114Z" }, + { url = "https://files.pythonhosted.org/packages/88/e5/9714def18c3a411809771a3fbcec70bffa764b9675afb00048a620fca604/pywinpty-2.0.15-cp312-cp312-win_amd64.whl", hash = "sha256:83a8f20b430bbc5d8957249f875341a60219a4e971580f2ba694fbfb54a45ebc", size = 1405243, upload-time = "2025-02-03T21:56:52.476Z" }, + { url = "https://files.pythonhosted.org/packages/fb/16/2ab7b3b7f55f3c6929e5f629e1a68362981e4e5fed592a2ed1cb4b4914a5/pywinpty-2.0.15-cp313-cp313-win_amd64.whl", hash = "sha256:ab5920877dd632c124b4ed17bc6dd6ef3b9f86cd492b963ffdb1a67b85b0f408", size = 1405020, upload-time = "2025-02-03T21:56:04.753Z" }, + { url = "https://files.pythonhosted.org/packages/7c/16/edef3515dd2030db2795dbfbe392232c7a0f3dc41b98e92b38b42ba497c7/pywinpty-2.0.15-cp313-cp313t-win_amd64.whl", hash = "sha256:a4560ad8c01e537708d2790dbe7da7d986791de805d89dd0d3697ca59e9e4901", size = 1404151, upload-time = "2025-02-03T21:55:53.628Z" }, ] [[package]] @@ -58,3 +964,358 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, ] + +[[package]] +name = "requests" +version = "2.33.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/34/64/8860370b167a9721e8956ae116825caff829224fbca0ca6e7bf8ddef8430/requests-2.33.0.tar.gz", hash = "sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652", size = 134232, upload-time = "2026-03-25T15:10:41.586Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/5d/c814546c2333ceea4ba42262d8c4d55763003e767fa169adc693bd524478/requests-2.33.0-py3-none-any.whl", hash = "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b", size = 65017, upload-time = "2026-03-25T15:10:40.382Z" }, +] + +[[package]] +name = "rich" +version = "14.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" }, +] + +[[package]] +name = "ruamel-yaml" +version = "0.18.17" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ruamel-yaml-clib", marker = "platform_python_implementation == 'CPython'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/2b/7a1f1ebcd6b3f14febdc003e658778d81e76b40df2267904ee6b13f0c5c6/ruamel_yaml-0.18.17.tar.gz", hash = "sha256:9091cd6e2d93a3a4b157ddb8fabf348c3de7f1fb1381346d985b6b247dcd8d3c", size = 149602, upload-time = "2025-12-17T20:02:55.757Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/fe/b6045c782f1fd1ae317d2a6ca1884857ce5c20f59befe6ab25a8603c43a7/ruamel_yaml-0.18.17-py3-none-any.whl", hash = "sha256:9c8ba9eb3e793efdf924b60d521820869d5bf0cb9c6f1b82d82de8295e290b9d", size = 121594, upload-time = "2025-12-17T20:02:07.657Z" }, +] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/97/60fda20e2fb54b83a61ae14648b0817c8f5d84a3821e40bfbdae1437026a/ruamel_yaml_clib-0.2.15.tar.gz", hash = "sha256:46e4cc8c43ef6a94885f72512094e482114a8a706d3c555a34ed4b0d20200600", size = 225794, upload-time = "2025-11-16T16:12:59.761Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/80/8ce7b9af532aa94dd83360f01ce4716264db73de6bc8efd22c32341f6658/ruamel_yaml_clib-0.2.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c583229f336682b7212a43d2fa32c30e643d3076178fb9f7a6a14dde85a2d8bd", size = 147998, upload-time = "2025-11-16T16:13:13.241Z" }, + { url = "https://files.pythonhosted.org/packages/53/09/de9d3f6b6701ced5f276d082ad0f980edf08ca67114523d1b9264cd5e2e0/ruamel_yaml_clib-0.2.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56ea19c157ed8c74b6be51b5fa1c3aff6e289a041575f0556f66e5fb848bb137", size = 132743, upload-time = "2025-11-16T16:13:14.265Z" }, + { url = "https://files.pythonhosted.org/packages/0e/f7/73a9b517571e214fe5c246698ff3ed232f1ef863c8ae1667486625ec688a/ruamel_yaml_clib-0.2.15-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5fea0932358e18293407feb921d4f4457db837b67ec1837f87074667449f9401", size = 731459, upload-time = "2025-11-16T20:22:44.338Z" }, + { url = "https://files.pythonhosted.org/packages/9b/a2/0dc0013169800f1c331a6f55b1282c1f4492a6d32660a0cf7b89e6684919/ruamel_yaml_clib-0.2.15-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef71831bd61fbdb7aa0399d5c4da06bea37107ab5c79ff884cc07f2450910262", size = 749289, upload-time = "2025-11-16T16:13:15.633Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ed/3fb20a1a96b8dc645d88c4072df481fe06e0289e4d528ebbdcc044ebc8b3/ruamel_yaml_clib-0.2.15-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:617d35dc765715fa86f8c3ccdae1e4229055832c452d4ec20856136acc75053f", size = 777630, upload-time = "2025-11-16T16:13:16.898Z" }, + { url = "https://files.pythonhosted.org/packages/60/50/6842f4628bc98b7aa4733ab2378346e1441e150935ad3b9f3c3c429d9408/ruamel_yaml_clib-0.2.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b45498cc81a4724a2d42273d6cfc243c0547ad7c6b87b4f774cb7bcc131c98d", size = 744368, upload-time = "2025-11-16T16:13:18.117Z" }, + { url = "https://files.pythonhosted.org/packages/d3/b0/128ae8e19a7d794c2e36130a72b3bb650ce1dd13fb7def6cf10656437dcf/ruamel_yaml_clib-0.2.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:def5663361f6771b18646620fca12968aae730132e104688766cf8a3b1d65922", size = 745233, upload-time = "2025-11-16T20:22:45.833Z" }, + { url = "https://files.pythonhosted.org/packages/75/05/91130633602d6ba7ce3e07f8fc865b40d2a09efd4751c740df89eed5caf9/ruamel_yaml_clib-0.2.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:014181cdec565c8745b7cbc4de3bf2cc8ced05183d986e6d1200168e5bb59490", size = 770963, upload-time = "2025-11-16T16:13:19.344Z" }, + { url = "https://files.pythonhosted.org/packages/fd/4b/fd4542e7f33d7d1bc64cc9ac9ba574ce8cf145569d21f5f20133336cdc8c/ruamel_yaml_clib-0.2.15-cp311-cp311-win32.whl", hash = "sha256:d290eda8f6ada19e1771b54e5706b8f9807e6bb08e873900d5ba114ced13e02c", size = 102640, upload-time = "2025-11-16T16:13:20.498Z" }, + { url = "https://files.pythonhosted.org/packages/bb/eb/00ff6032c19c7537371e3119287999570867a0eafb0154fccc80e74bf57a/ruamel_yaml_clib-0.2.15-cp311-cp311-win_amd64.whl", hash = "sha256:bdc06ad71173b915167702f55d0f3f027fc61abd975bd308a0968c02db4a4c3e", size = 121996, upload-time = "2025-11-16T16:13:21.855Z" }, + { url = "https://files.pythonhosted.org/packages/72/4b/5fde11a0722d676e469d3d6f78c6a17591b9c7e0072ca359801c4bd17eee/ruamel_yaml_clib-0.2.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cb15a2e2a90c8475df45c0949793af1ff413acfb0a716b8b94e488ea95ce7cff", size = 149088, upload-time = "2025-11-16T16:13:22.836Z" }, + { url = "https://files.pythonhosted.org/packages/85/82/4d08ac65ecf0ef3b046421985e66301a242804eb9a62c93ca3437dc94ee0/ruamel_yaml_clib-0.2.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:64da03cbe93c1e91af133f5bec37fd24d0d4ba2418eaf970d7166b0a26a148a2", size = 134553, upload-time = "2025-11-16T16:13:24.151Z" }, + { url = "https://files.pythonhosted.org/packages/b9/cb/22366d68b280e281a932403b76da7a988108287adff2bfa5ce881200107a/ruamel_yaml_clib-0.2.15-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f6d3655e95a80325b84c4e14c080b2470fe4f33b6846f288379ce36154993fb1", size = 737468, upload-time = "2025-11-16T20:22:47.335Z" }, + { url = "https://files.pythonhosted.org/packages/71/73/81230babf8c9e33770d43ed9056f603f6f5f9665aea4177a2c30ae48e3f3/ruamel_yaml_clib-0.2.15-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71845d377c7a47afc6592aacfea738cc8a7e876d586dfba814501d8c53c1ba60", size = 753349, upload-time = "2025-11-16T16:13:26.269Z" }, + { url = "https://files.pythonhosted.org/packages/61/62/150c841f24cda9e30f588ef396ed83f64cfdc13b92d2f925bb96df337ba9/ruamel_yaml_clib-0.2.15-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e5499db1ccbc7f4b41f0565e4f799d863ea720e01d3e99fa0b7b5fcd7802c9", size = 788211, upload-time = "2025-11-16T16:13:27.441Z" }, + { url = "https://files.pythonhosted.org/packages/30/93/e79bd9cbecc3267499d9ead919bd61f7ddf55d793fb5ef2b1d7d92444f35/ruamel_yaml_clib-0.2.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4b293a37dc97e2b1e8a1aec62792d1e52027087c8eea4fc7b5abd2bdafdd6642", size = 743203, upload-time = "2025-11-16T16:13:28.671Z" }, + { url = "https://files.pythonhosted.org/packages/8d/06/1eb640065c3a27ce92d76157f8efddb184bd484ed2639b712396a20d6dce/ruamel_yaml_clib-0.2.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:512571ad41bba04eac7268fe33f7f4742210ca26a81fe0c75357fa682636c690", size = 747292, upload-time = "2025-11-16T20:22:48.584Z" }, + { url = "https://files.pythonhosted.org/packages/a5/21/ee353e882350beab65fcc47a91b6bdc512cace4358ee327af2962892ff16/ruamel_yaml_clib-0.2.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5e9f630c73a490b758bf14d859a39f375e6999aea5ddd2e2e9da89b9953486a", size = 771624, upload-time = "2025-11-16T16:13:29.853Z" }, + { url = "https://files.pythonhosted.org/packages/57/34/cc1b94057aa867c963ecf9ea92ac59198ec2ee3a8d22a126af0b4d4be712/ruamel_yaml_clib-0.2.15-cp312-cp312-win32.whl", hash = "sha256:f4421ab780c37210a07d138e56dd4b51f8642187cdfb433eb687fe8c11de0144", size = 100342, upload-time = "2025-11-16T16:13:31.067Z" }, + { url = "https://files.pythonhosted.org/packages/b3/e5/8925a4208f131b218f9a7e459c0d6fcac8324ae35da269cb437894576366/ruamel_yaml_clib-0.2.15-cp312-cp312-win_amd64.whl", hash = "sha256:2b216904750889133d9222b7b873c199d48ecbb12912aca78970f84a5aa1a4bc", size = 119013, upload-time = "2025-11-16T16:13:32.164Z" }, + { url = "https://files.pythonhosted.org/packages/17/5e/2f970ce4c573dc30c2f95825f2691c96d55560268ddc67603dc6ea2dd08e/ruamel_yaml_clib-0.2.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4dcec721fddbb62e60c2801ba08c87010bd6b700054a09998c4d09c08147b8fb", size = 147450, upload-time = "2025-11-16T16:13:33.542Z" }, + { url = "https://files.pythonhosted.org/packages/d6/03/a1baa5b94f71383913f21b96172fb3a2eb5576a4637729adbf7cd9f797f8/ruamel_yaml_clib-0.2.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:65f48245279f9bb301d1276f9679b82e4c080a1ae25e679f682ac62446fac471", size = 133139, upload-time = "2025-11-16T16:13:34.587Z" }, + { url = "https://files.pythonhosted.org/packages/dc/19/40d676802390f85784235a05788fd28940923382e3f8b943d25febbb98b7/ruamel_yaml_clib-0.2.15-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:46895c17ead5e22bea5e576f1db7e41cb273e8d062c04a6a49013d9f60996c25", size = 731474, upload-time = "2025-11-16T20:22:49.934Z" }, + { url = "https://files.pythonhosted.org/packages/ce/bb/6ef5abfa43b48dd55c30d53e997f8f978722f02add61efba31380d73e42e/ruamel_yaml_clib-0.2.15-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3eb199178b08956e5be6288ee0b05b2fb0b5c1f309725ad25d9c6ea7e27f962a", size = 748047, upload-time = "2025-11-16T16:13:35.633Z" }, + { url = "https://files.pythonhosted.org/packages/ff/5d/e4f84c9c448613e12bd62e90b23aa127ea4c46b697f3d760acc32cb94f25/ruamel_yaml_clib-0.2.15-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d1032919280ebc04a80e4fb1e93f7a738129857eaec9448310e638c8bccefcf", size = 782129, upload-time = "2025-11-16T16:13:36.781Z" }, + { url = "https://files.pythonhosted.org/packages/de/4b/e98086e88f76c00c88a6bcf15eae27a1454f661a9eb72b111e6bbb69024d/ruamel_yaml_clib-0.2.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab0df0648d86a7ecbd9c632e8f8d6b21bb21b5fc9d9e095c796cacf32a728d2d", size = 736848, upload-time = "2025-11-16T16:13:37.952Z" }, + { url = "https://files.pythonhosted.org/packages/0c/5c/5964fcd1fd9acc53b7a3a5d9a05ea4f95ead9495d980003a557deb9769c7/ruamel_yaml_clib-0.2.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:331fb180858dd8534f0e61aa243b944f25e73a4dae9962bd44c46d1761126bbf", size = 741630, upload-time = "2025-11-16T20:22:51.718Z" }, + { url = "https://files.pythonhosted.org/packages/07/1e/99660f5a30fceb58494598e7d15df883a07292346ef5696f0c0ae5dee8c6/ruamel_yaml_clib-0.2.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fd4c928ddf6bce586285daa6d90680b9c291cfd045fc40aad34e445d57b1bf51", size = 766619, upload-time = "2025-11-16T16:13:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/36/2f/fa0344a9327b58b54970e56a27b32416ffbcfe4dcc0700605516708579b2/ruamel_yaml_clib-0.2.15-cp313-cp313-win32.whl", hash = "sha256:bf0846d629e160223805db9fe8cc7aec16aaa11a07310c50c8c7164efa440aec", size = 100171, upload-time = "2025-11-16T16:13:40.456Z" }, + { url = "https://files.pythonhosted.org/packages/06/c4/c124fbcef0684fcf3c9b72374c2a8c35c94464d8694c50f37eef27f5a145/ruamel_yaml_clib-0.2.15-cp313-cp313-win_amd64.whl", hash = "sha256:45702dfbea1420ba3450bb3dd9a80b33f0badd57539c6aac09f42584303e0db6", size = 118845, upload-time = "2025-11-16T16:13:41.481Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "socksio" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/5c/48a7d9495be3d1c651198fd99dbb6ce190e2274d0f28b9051307bdec6b85/socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac", size = 19055, upload-time = "2020-04-17T15:50:34.664Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/c3/6eeb6034408dac0fa653d126c9204ade96b819c936e136c5e8a6897eee9c/socksio-1.0.0-py3-none-any.whl", hash = "sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3", size = 12763, upload-time = "2020-04-17T15:50:31.878Z" }, +] + +[[package]] +name = "starlette" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6", size = 73632, upload-time = "2026-06-12T09:23:10.017Z" }, +] + +[[package]] +name = "tenacity" +version = "9.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413, upload-time = "2026-02-07T10:45:33.841Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload-time = "2026-02-07T10:45:32.24Z" }, +] + +[[package]] +name = "termcolor" +version = "3.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434, upload-time = "2025-12-29T12:55:21.882Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734, upload-time = "2025-12-29T12:55:20.718Z" }, +] + +[[package]] +name = "tqdm" +version = "4.70.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/3b/6c24bec5be5e743ffd99576daa5cc077722fc7d5bbc00bd133fa0c698dc6/tqdm-4.70.0.tar.gz", hash = "sha256:55b0b0dbd97462d06ebee91e4dac24ed4d4702be82b24f07e6c1d27e08cea220", size = 795438, upload-time = "2026-07-27T11:33:15.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl", hash = "sha256:7f585706bfddbdebf89daac705b2dfcc16890130727d3197ca62c732b4310953", size = 80184, upload-time = "2026-07-27T11:33:13.167Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, +] + +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.51.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/65/b7c6c443ccc58678c91e1e973bbe2a878591538655d6e1d47f24ba1c51f3/uvicorn-0.51.0.tar.gz", hash = "sha256:f6f4b69b657c312f516dd2d268ab9ae6f254b11e4bac504f37b2ab58b24dd0b0", size = 94412, upload-time = "2026-07-08T10:59:05.962Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/ec/dbb7e5a6b91f86bfb9eb7d2988a2730907b6a729875b949c7f022e8b88fa/uvicorn-0.51.0-py3-none-any.whl", hash = "sha256:5d38af6cd620f2ae3849fb44fd4879e0890aa1febe8d47eb355fb45d93fe6a5b", size = 73219, upload-time = "2026-07-08T10:59:04.44Z" }, +] + +[package.optional-dependencies] +standard = [ + { name = "httptools" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, + { name = "watchfiles" }, + { name = "websockets" }, +] + +[[package]] +name = "uvloop" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/d5/69900f7883235562f1f50d8184bb7dd84a2fb61e9ec63f3782546fdbd057/uvloop-0.22.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c60ebcd36f7b240b30788554b6f0782454826a0ed765d8430652621b5de674b9", size = 1352420, upload-time = "2025-10-16T22:16:21.187Z" }, + { url = "https://files.pythonhosted.org/packages/a8/73/c4e271b3bce59724e291465cc936c37758886a4868787da0278b3b56b905/uvloop-0.22.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b7f102bf3cb1995cfeaee9321105e8f5da76fdb104cdad8986f85461a1b7b77", size = 748677, upload-time = "2025-10-16T22:16:22.558Z" }, + { url = "https://files.pythonhosted.org/packages/86/94/9fb7fad2f824d25f8ecac0d70b94d0d48107ad5ece03769a9c543444f78a/uvloop-0.22.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53c85520781d84a4b8b230e24a5af5b0778efdb39142b424990ff1ef7c48ba21", size = 3753819, upload-time = "2025-10-16T22:16:23.903Z" }, + { url = "https://files.pythonhosted.org/packages/74/4f/256aca690709e9b008b7108bc85fba619a2bc37c6d80743d18abad16ee09/uvloop-0.22.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56a2d1fae65fd82197cb8c53c367310b3eabe1bbb9fb5a04d28e3e3520e4f702", size = 3804529, upload-time = "2025-10-16T22:16:25.246Z" }, + { url = "https://files.pythonhosted.org/packages/7f/74/03c05ae4737e871923d21a76fe28b6aad57f5c03b6e6bfcfa5ad616013e4/uvloop-0.22.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40631b049d5972c6755b06d0bfe8233b1bd9a8a6392d9d1c45c10b6f9e9b2733", size = 3621267, upload-time = "2025-10-16T22:16:26.819Z" }, + { url = "https://files.pythonhosted.org/packages/75/be/f8e590fe61d18b4a92070905497aec4c0e64ae1761498cad09023f3f4b3e/uvloop-0.22.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:535cc37b3a04f6cd2c1ef65fa1d370c9a35b6695df735fcff5427323f2cd5473", size = 3723105, upload-time = "2025-10-16T22:16:28.252Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ff/7f72e8170be527b4977b033239a83a68d5c881cc4775fca255c677f7ac5d/uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42", size = 1359936, upload-time = "2025-10-16T22:16:29.436Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c6/e5d433f88fd54d81ef4be58b2b7b0cea13c442454a1db703a1eea0db1a59/uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6", size = 752769, upload-time = "2025-10-16T22:16:30.493Z" }, + { url = "https://files.pythonhosted.org/packages/24/68/a6ac446820273e71aa762fa21cdcc09861edd3536ff47c5cd3b7afb10eeb/uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370", size = 4317413, upload-time = "2025-10-16T22:16:31.644Z" }, + { url = "https://files.pythonhosted.org/packages/5f/6f/e62b4dfc7ad6518e7eff2516f680d02a0f6eb62c0c212e152ca708a0085e/uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4", size = 4426307, upload-time = "2025-10-16T22:16:32.917Z" }, + { url = "https://files.pythonhosted.org/packages/90/60/97362554ac21e20e81bcef1150cb2a7e4ffdaf8ea1e5b2e8bf7a053caa18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2", size = 4131970, upload-time = "2025-10-16T22:16:34.015Z" }, + { url = "https://files.pythonhosted.org/packages/99/39/6b3f7d234ba3964c428a6e40006340f53ba37993f46ed6e111c6e9141d18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0", size = 4296343, upload-time = "2025-10-16T22:16:35.149Z" }, + { url = "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705", size = 1358611, upload-time = "2025-10-16T22:16:36.833Z" }, + { url = "https://files.pythonhosted.org/packages/d2/14/e301ee96a6dc95224b6f1162cd3312f6d1217be3907b79173b06785f2fe7/uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8", size = 751811, upload-time = "2025-10-16T22:16:38.275Z" }, + { url = "https://files.pythonhosted.org/packages/b7/02/654426ce265ac19e2980bfd9ea6590ca96a56f10c76e63801a2df01c0486/uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d", size = 4288562, upload-time = "2025-10-16T22:16:39.375Z" }, + { url = "https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e", size = 4366890, upload-time = "2025-10-16T22:16:40.547Z" }, + { url = "https://files.pythonhosted.org/packages/d2/53/8369e5219a5855869bcee5f4d317f6da0e2c669aecf0ef7d371e3d084449/uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e", size = 4119472, upload-time = "2025-10-16T22:16:41.694Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ba/d69adbe699b768f6b29a5eec7b47dd610bd17a69de51b251126a801369ea/uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad", size = 4239051, upload-time = "2025-10-16T22:16:43.224Z" }, +] + +[[package]] +name = "watchfiles" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/41/5e1a4bb12aac5f1493fa1bdc11154eca3b258ca4eba65d39c473fe19d8e9/watchfiles-1.2.0.tar.gz", hash = "sha256:c995fba777f1ea992f090f9236e9284cf7a5d1a0130dd5a3d82c598cacd76838", size = 108252, upload-time = "2026-05-18T04:32:04.251Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/3d/8024c801df84d1587740d0359e7fdd80afeae3d159011f3d5376dd82f18e/watchfiles-1.2.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:704fd259e332e01f9b9c178f4bce9e49027e5587cc2600eeeaf8e76e1c846201", size = 400242, upload-time = "2026-05-18T04:31:19.014Z" }, + { url = "https://files.pythonhosted.org/packages/87/5b/f4dfd45323e949984a3a7f9dc31d1cbb049921e7d98253488dda72ccdaa9/watchfiles-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6543cf55d170003296d185c0af981f3e1311564907e1f4e08671fc7693a890a5", size = 394562, upload-time = "2026-05-18T04:30:08.46Z" }, + { url = "https://files.pythonhosted.org/packages/98/d8/19483ef075d601c409bce8bcbb5c0f81a10876fff870400568f08ce484a1/watchfiles-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89d8c2394a065ca86f5d2910ff263ae67c127e1376ccc4f9fc35c71db879f80a", size = 456611, upload-time = "2026-05-18T04:30:45.723Z" }, + { url = "https://files.pythonhosted.org/packages/b1/6a/cc81fbe7ee42f2f22e661a6e12def7807e01b14b2f39e0ff83fd373fd307/watchfiles-1.2.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:772b80df316480d894a0e3165fdd19cf77f5d17f9a787f94029465ad0e3529d1", size = 461379, upload-time = "2026-05-18T04:31:29.292Z" }, + { url = "https://files.pythonhosted.org/packages/b1/57/7e669002082c0a0f4fb5113bb70125f7110124b846b0a11bc5ae8e90eac1/watchfiles-1.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d158cd89df6053823533e06fb1d73c549133bff5f0396170c0e53d9559340717", size = 493556, upload-time = "2026-05-18T04:30:05.44Z" }, + { url = "https://files.pythonhosted.org/packages/45/7d/f60a2b19807b21fe8281f3a8da4f59eef0d5f96825ac4680ba2d4f2ebf91/watchfiles-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d516b3283a758e087841aedb8031549fb41ced08f3db10aa6d2bf32dc042525b", size = 575255, upload-time = "2026-05-18T04:30:40.568Z" }, + { url = "https://files.pythonhosted.org/packages/bd/49/77f5b5e6efbcd57482f74948ebb1b97e5c0046d6b61475042d830c84b3ff/watchfiles-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:53b2290c92e0506d102cd448fbc610d87079553f86caa39d67440856a8b8bba5", size = 467052, upload-time = "2026-05-18T04:31:17.942Z" }, + { url = "https://files.pythonhosted.org/packages/ee/5a/73e2959af1b97fd5d556f9a8bdba017be23ceeef731869d5eaa0a753d5a3/watchfiles-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a711b51aec4370d0dcda5b6c09463206f133a5759341d7744b953a7b62e1100e", size = 456858, upload-time = "2026-05-18T04:30:30.182Z" }, + { url = "https://files.pythonhosted.org/packages/50/57/1bc8c27fad7e6c19bddee15d276dbb6ab72480ec01c127afff1673aee417/watchfiles-1.2.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:e2ca07fa7d89195ec0865d3d285666286740bfa83d83e5cee204043a31ecc165", size = 467579, upload-time = "2026-05-18T04:32:15.897Z" }, + { url = "https://files.pythonhosted.org/packages/09/6c/3c2e44edba3553c5e3c3b8c8a2a6dee6b9e12ae2cf4bd2378bebf9dc3038/watchfiles-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e0618518f282c4ebff60f5e5b1247b6d91bb8b9f4476947563a1e74acc66f3c6", size = 633253, upload-time = "2026-05-18T04:31:37.123Z" }, + { url = "https://files.pythonhosted.org/packages/30/c2/d8c84a882ab39bbefcc4915ab3e91830b7a7e990c5570b0b69075aba3faf/watchfiles-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0d191c054d0715c3c95c99df9b8dbf6fd096d8c1e021e8f212e1bd8bc444ccb5", size = 660713, upload-time = "2026-05-18T04:31:24.62Z" }, + { url = "https://files.pythonhosted.org/packages/a9/07/f97736a5fc605364fe67b25e9fa4a6965dfd4840d50c406ada507e9d735f/watchfiles-1.2.0-cp311-cp311-win32.whl", hash = "sha256:9342472aff9b093c5acd4f6d8f70ae0937964ab56542502bcf5579782da69ae8", size = 277222, upload-time = "2026-05-18T04:31:21.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/99/2b04981977fc2608afd60360d928c6aecf6b950292ca221d98f4005f6694/watchfiles-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:dbd6c97045dad81227c8d040173da044c1de08de64a5ea8b555da4aee1d5fa22", size = 290274, upload-time = "2026-05-18T04:31:45.966Z" }, + { url = "https://files.pythonhosted.org/packages/3c/74/f7f58a7075ee9cf612b0cfcddb78b8cd8234f0742d6f0075cf0da2dde1c6/watchfiles-1.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:57a2d9fa4fb4c2ecae57b13dfff2c7ab53e21a2ba674fe9f05506680fcdcc0d7", size = 283460, upload-time = "2026-05-18T04:31:39.126Z" }, + { url = "https://files.pythonhosted.org/packages/b8/2f/e42c992d2afda3108ea1c02acecc991b9f31d05c14adc2a7cee9ee211fc4/watchfiles-1.2.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:bc13eb17538be00c874699dc0abe4ee2bc8d50bb1166a6b9e175ef3fd7eb8f26", size = 400115, upload-time = "2026-05-18T04:32:02.06Z" }, + { url = "https://files.pythonhosted.org/packages/5f/8f/6af2ea19065c91d8b0ea3516fdfc8c0d349f407e8e9fbf4e5a17360de8ad/watchfiles-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d95ddc1eb6914154253d239089900813f6a767e174b8e6a50e7fdacb7e4236c", size = 393659, upload-time = "2026-05-18T04:30:50.951Z" }, + { url = "https://files.pythonhosted.org/packages/13/01/b32a967c56fb3e3e5be3db52c3d3b87fa4513aa367d8ed1ad96d42952e5f/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f70d8b291ef6e88d19b1f297a6905ddb978888d9272b0d05e6f53309856bcfc", size = 453207, upload-time = "2026-05-18T04:31:04.231Z" }, + { url = "https://files.pythonhosted.org/packages/04/98/97557a812180338cb1abd32e1cffcc4588f59b5f23e0cb006b2ba95ba64a/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:56d8641cf834c2836922899105bd3ce3d0dfc69291d52edf0b4d0436829b34c0", size = 459273, upload-time = "2026-05-18T04:31:50.377Z" }, + { url = "https://files.pythonhosted.org/packages/e8/a8/b4b08dcb7653b8087c6586f7ce649505900e866bbcfe40dc9587af02e686/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2581a94056e55d7d0a31a823ea92bf73749c489ca2285bfdc0fbe6b2bb49d50c", size = 489927, upload-time = "2026-05-18T04:31:42.485Z" }, + { url = "https://files.pythonhosted.org/packages/50/94/3dceea03545d2e5ddfd839f0ddd5e1cecbf1697b5a428d5ba11cef6af95d/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41bc1199f7523b3f82843c88cbb979180c949caef0342cf90968f178e5d49b01", size = 570476, upload-time = "2026-05-18T04:31:03.071Z" }, + { url = "https://files.pythonhosted.org/packages/cc/f2/d39a5450c3532092b91f81d274360e613c2371bc874a89c7a1a3c5e8d138/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7571e4464cb6e434958f867f7f730b8ab0b75e3f8e5eac0499168486ab3c33a8", size = 465650, upload-time = "2026-05-18T04:30:12.701Z" }, + { url = "https://files.pythonhosted.org/packages/22/24/ed72f68cbc1333ca9b9f2200aa048bb6658ae41709bc1caad4310f4bdffd/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e53a384f76b631c3ae5334ce6a52f0baa3a911eb94a4eac7f160079868b716d5", size = 456398, upload-time = "2026-05-18T04:30:13.784Z" }, + { url = "https://files.pythonhosted.org/packages/0d/64/982ef4a4e5bab5b6e5b6becc8cd5e732f6130a78b855f0abec6439a9a135/watchfiles-1.2.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:d20029a60a71a052a24c4db7673bc4de39ab89adbaccbfb5d67987c5d73f424d", size = 465140, upload-time = "2026-05-18T04:31:52.111Z" }, + { url = "https://files.pythonhosted.org/packages/a0/0c/95282abf4ed680b6096010bcfc30c5fa7a041fc5aa5a2ad17a2cc6c75bba/watchfiles-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2cb93af48550faf1cea04c303107c8b75833de7013e57ce27d3b8d21d8d0f58c", size = 630259, upload-time = "2026-05-18T04:31:25.676Z" }, + { url = "https://files.pythonhosted.org/packages/30/45/607c1de1530c4bdcf2cf1d1ecc2505ddba5d96bd43ba9f2b0e79876f850f/watchfiles-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2995c176de7692b86a2e4c58d9ec718f753150a979cb4a754e2b4ffa38e70906", size = 659859, upload-time = "2026-05-18T04:30:24.333Z" }, + { url = "https://files.pythonhosted.org/packages/fa/08/d9e2e0f9e8e6791d33aefc694ad7eefa7f901f63caff84a81ded38692f9c/watchfiles-1.2.0-cp312-cp312-win32.whl", hash = "sha256:7a2cffd17d27d2ecbb310c2b1d8174f222a5495b1a721894afa88ec11e25b898", size = 275480, upload-time = "2026-05-18T04:30:31.307Z" }, + { url = "https://files.pythonhosted.org/packages/1c/e6/9d42569c0102645cc8cea5d8c7d8a1e9d4ada2cb7f05f75e554b8aa2202a/watchfiles-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:f155b3a1b2a5fc89cdc70d47ee5d54e3b75e88efa34982028a35daef9ba00379", size = 288718, upload-time = "2026-05-18T04:32:10.745Z" }, + { url = "https://files.pythonhosted.org/packages/0a/26/88e0dc6ee3898169d7fa22bb6a69cabf2502d2ee25cb8c876d1262d204f8/watchfiles-1.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:8fa585ede612ee9f9e91b18bebf9ba11b9ae29a4e3a0d0cf6fca3e382133f0d5", size = 281026, upload-time = "2026-05-18T04:30:22.23Z" }, + { url = "https://files.pythonhosted.org/packages/d1/4d/70a7feced9f87e2ff26dba42667290f41694fc64646c67261fbb8cab5d5c/watchfiles-1.2.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:01ea8d66f0693b9b60a6541c8d10263091ca9a9060d242f3c1f3143f9aad2c98", size = 399730, upload-time = "2026-05-18T04:31:38.162Z" }, + { url = "https://files.pythonhosted.org/packages/31/3a/0da302f2307aee316922806ebd5726c542cbd787c938271cf14a074c7daf/watchfiles-1.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ba0480b9a74af058f43b337e937a451e109295c420916d68ad24e3dc02f5e44", size = 392842, upload-time = "2026-05-18T04:30:27.051Z" }, + { url = "https://files.pythonhosted.org/packages/db/ef/d5bdb705c224dbc256aa0c1ec47bf4e61ec52558f2afb44a71a1fe4d7015/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f34e26a19f91f710c08e0183429f0d1d15df734e6bc78c31e77b9ea9c433658", size = 452989, upload-time = "2026-05-18T04:31:11.945Z" }, + { url = "https://files.pythonhosted.org/packages/71/29/5495f2c1661949ef7a35e4d71111d129cfe7606414a26887a919d0a55406/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b4e77f6a55f858504069abd35d336a637555c09bca453dde1ee1e5ada8a6a1fb", size = 458978, upload-time = "2026-05-18T04:30:52.606Z" }, + { url = "https://files.pythonhosted.org/packages/d5/8c/7f9c07c433811c2fffd93e13fdfb7135de9aab5f2ae41be08960fa0047dc/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cb4d80e212f116474a545c21c912b445f16bb0cef9e6a73a498164223e14e2f", size = 490248, upload-time = "2026-05-18T04:31:36.003Z" }, + { url = "https://files.pythonhosted.org/packages/3c/11/d93632febc52fbc21be90231bb7c17fd5387f46c9076fd40a5f9c2ae6910/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b974946a10af379d425e2eef5b62f5c6ebeaccf91d45eaad6f5b27ecd4f91aa0", size = 571847, upload-time = "2026-05-18T04:31:10.862Z" }, + { url = "https://files.pythonhosted.org/packages/55/b4/383173e73aabb07ad1d9c7aa859d95437ac46a6d6a1e11005facda0c9d19/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86bc13c25a8d1fcd70b51d0ce7c9b65e90de5666fcbfd3e34957cc73ee19aeb5", size = 465974, upload-time = "2026-05-18T04:30:17.006Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6c/89b1a230a78f57c52dd8893adb1f92f94411721b6ec12596c56d98c74356/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca148d73dea36c9763aaa351e4d7a51780ec1584217c45276f4fe8239c768b71", size = 454782, upload-time = "2026-05-18T04:30:35.656Z" }, + { url = "https://files.pythonhosted.org/packages/24/62/1732118367cfff0a9fce3bf62ff4bfded09ef5df21d9d446b858b3f70a96/watchfiles-1.2.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:c525543d91961c6955b2636b308569e84a1d1c5f5f2932041ab9ef46422f43e3", size = 465182, upload-time = "2026-05-18T04:30:20.846Z" }, + { url = "https://files.pythonhosted.org/packages/28/96/716f7e5f51339bf22963f3345f9f27d7f3b30e2eadc597e257c881dd3c53/watchfiles-1.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a204794696ffb8f9b10fba6f7cb5216d42f3b2b71860ccac6b6e42f5f10973b0", size = 629841, upload-time = "2026-05-18T04:31:05.397Z" }, + { url = "https://files.pythonhosted.org/packages/4c/fe/c40783950fd771ccf66ab3ec2722d188a9af1c7f96c6e811f36e40c6e03f/watchfiles-1.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:10d86db20695afe7997ac9e1717637d6714a8d0220458c33f3d2061f54cec427", size = 658028, upload-time = "2026-05-18T04:31:48.22Z" }, + { url = "https://files.pythonhosted.org/packages/71/72/4508db1856d1d87fcbb3b63f4839bab1b5682cb0e8d224d122263c09654a/watchfiles-1.2.0-cp313-cp313-win32.whl", hash = "sha256:eb283ee99e21ad6443c8cdb06ac5b34b1308c329cbdf03fa02b445363714c799", size = 275183, upload-time = "2026-05-18T04:30:59.57Z" }, + { url = "https://files.pythonhosted.org/packages/f9/36/14b76ca57652e5cc5fd1c11f32a261292c08a0d19a00351013c2549cbfb2/watchfiles-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:a0f27f01bee51861392bb6b7c4fdb290b27d1eb194e9e28788d68102a0e898d9", size = 288059, upload-time = "2026-05-18T04:32:07.937Z" }, + { url = "https://files.pythonhosted.org/packages/1b/8d/0a85e395398d8d20fadfe5c5d32c726eee17a519e78fb356f2cf7531bffe/watchfiles-1.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:3651aa7058595e9cfb75d35dd5ada2bf9f48a5b8a0f3562821d3e210c507e077", size = 280186, upload-time = "2026-05-18T04:31:54.484Z" }, + { url = "https://files.pythonhosted.org/packages/37/68/36db056f1fdcc5f07302f56e631774d6835bcd6fa3ace402304621d5f9e5/watchfiles-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:faea288b6f0ab1902ef08f4ca6de005dccf856c4e0c4f21b8c5fce02d90a1b08", size = 399031, upload-time = "2026-05-18T04:30:44.576Z" }, + { url = "https://files.pythonhosted.org/packages/c1/64/01a9d6f66a82a5c101ce939274106cc72759d62427e153f01edd2b9f87c2/watchfiles-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:01859b11fd9fbca670f4d5da00fbac282cfea9bd67a2125d8b2833a3b5617ea9", size = 391205, upload-time = "2026-05-18T04:30:25.413Z" }, + { url = "https://files.pythonhosted.org/packages/84/2c/0a44fe058cb4bb7b8ede6b6670698bbb7c0400740e378d00022189b7b31d/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fff610d7bb2256a317bb1e96f0d7862c7aa8076733ee5df0fd41bbe76a24a4f4", size = 451892, upload-time = "2026-05-18T04:32:14.005Z" }, + { url = "https://files.pythonhosted.org/packages/67/a1/351e0d56cd35e6488b5c8b4fb11a809a5bc923e8fe8fed9faf8920be0c89/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b141a4891c995a039cd89e9a49e62df1dc8a559a5d1a6e4c7106d16c12777a55", size = 458867, upload-time = "2026-05-18T04:31:22.279Z" }, + { url = "https://files.pythonhosted.org/packages/d5/7d/9d09605187f1b838998624049fcf8bf47b73c1a3b76901fcac1782f62277/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f22943b7770483f6ea0721c6b11d022947a98eb0acae14694de034f4d0d38925", size = 490217, upload-time = "2026-05-18T04:31:43.657Z" }, + { url = "https://files.pythonhosted.org/packages/60/5d/a17a16eccb182f04188cd308ec24b1a71a9b5c4e7098269cf35d9fa56d02/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bc6195825b7dcd217968bb1f801a60fd4c16e8eeab5bedc7fe917d7d5995ab4", size = 571458, upload-time = "2026-05-18T04:32:11.875Z" }, + { url = "https://files.pythonhosted.org/packages/d3/3d/4dd457062083ab1938e5dfd45032eb425cee2ac817287ca8ff4356183e5d/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4a4b147f5dca2a5d325a06a832fb43f345751adfbc63204aec30e0d9ca965a2", size = 464707, upload-time = "2026-05-18T04:30:43.492Z" }, + { url = "https://files.pythonhosted.org/packages/c6/71/ea8c57b128f5383de74d0c7d2d9c57ad7c9a65a930c451bd25d524b295b7/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4543579a9bdb0c9560039b4ffddbdb39545707659fbc430ce4c10f3f68d557f9", size = 454663, upload-time = "2026-05-18T04:30:16.061Z" }, + { url = "https://files.pythonhosted.org/packages/53/fd/2e812bf938406d7db351f0703ddd3fc6c061cf30d96153a77bc79a943a44/watchfiles-1.2.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:20aa0e708b920bde876a4aa82dc7dd6ebea228a63a67cda6632c2fc87b787efa", size = 463537, upload-time = "2026-05-18T04:31:44.9Z" }, + { url = "https://files.pythonhosted.org/packages/86/56/d17a7f1dd1bc3035f1072694a551301272f1739c2d8e319c927cb9e29b38/watchfiles-1.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:d413349d565dab74297f2a63e84a097936be69bf8f3b3801f27f380e32040f44", size = 629194, upload-time = "2026-05-18T04:31:14.141Z" }, + { url = "https://files.pythonhosted.org/packages/be/06/f1ff66bf5cae50aa4062779a0ecd0bbaf15e466195719074078947d9a17d/watchfiles-1.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f28b2725eb8cce327b9b3ab02415c853011dc55c95832fe90de6bc56f5315f72", size = 656194, upload-time = "2026-05-18T04:31:47.14Z" }, + { url = "https://files.pythonhosted.org/packages/23/f4/7513ef1e85fc4c6331b59479d6d72661fc391fbe543678052ac72c8b6c19/watchfiles-1.2.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:4674d49eb94706dfe666c069fc0a1b646ffcf920473492e209f6d5f60d3f0cc2", size = 403050, upload-time = "2026-05-18T04:30:36.753Z" }, + { url = "https://files.pythonhosted.org/packages/27/0b/a54103cfd732bb703c7a749222011a0483ef3705948dae3b203158601119/watchfiles-1.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:094b9b70103d4e963499bdea001ee3c2697b144cd9ae6218a62c0f89ec9e31db", size = 396629, upload-time = "2026-05-18T04:32:03.268Z" }, + { url = "https://files.pythonhosted.org/packages/5e/2c/73f31a3b893886206c3f54d73e8ad8dee58cdb2f69ad2622e0a8a9e07f4e/watchfiles-1.2.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0ef001f8c25ad0fa9529f914c1600647ecd0f542d11c19b7894768c67b6acb7", size = 457318, upload-time = "2026-05-18T04:31:01.932Z" }, + { url = "https://files.pythonhosted.org/packages/e9/f9/45d021e4a5cc7b9dd567f7cbb06d3b75f751a690063fb6cc7ec60f4e46b7/watchfiles-1.2.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a88fc94e647bc4eec523f1caa540258eb71d14278b9daf72fa1e2658a98df0f0", size = 457771, upload-time = "2026-05-18T04:30:56.331Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.8.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/34/74/c6428f875774288bec1396f5bfcbc2d925700a4dad61727fd5f2b12f249d/wcwidth-0.8.2.tar.gz", hash = "sha256:91fbef97204b96a3d4d421609b80340b760cf33e26da123ff243d76b1fda8dda", size = 1466253, upload-time = "2026-06-29T18:11:11.601Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl", hash = "sha256:d63947694a0539a1d51e01eda7caf800c291020e6cdd7e28ad7b14dd33ad4f85", size = 323166, upload-time = "2026-06-29T18:11:09.888Z" }, +] + +[[package]] +name = "websockets" +version = "15.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, + { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, + { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, + { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, + { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, + { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, + { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, + { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, + { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, + { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, + { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, + { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, + { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, + { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, + { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, + { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, + { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, + { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, + { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, + { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, + { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, + { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, + { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, + { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, +] diff --git a/docs/getting-started/install.mdx b/docs/getting-started/install.mdx index 340d2b2e..87267f16 100644 --- a/docs/getting-started/install.mdx +++ b/docs/getting-started/install.mdx @@ -7,48 +7,120 @@ SPDX-License-Identifier: Apache-2.0 */} ## Package Installation Method -NeMo Fabric is separated into two distinct parts: -- NeMo Fabric Runtime: This contains the core functionality of NeMo Fabric. -- NeMo Fabric Adapters: These provide integration with agent harnesses. These need to be installed into - the same environment as the agent harness which may or may not be the same environment as the NeMo Fabric runtime. +The `nemo-fabric` package installs the NeMo Fabric runtime. Harness adapters can +run in that environment or in a separate environment with their harness +dependencies. ### Supported Python Versions -- Python version 3.11 - 3.14 -NeMo Fabric supports Python versions 3.11-3.14, however some of the integrations and adapters may have -additional requirements. Specifically the Hermes Agent adapter doesn't support Python 3.14 yet, and the Harbor -integration requires Python 3.12 or later. +NeMo Fabric supports Python 3.11 through 3.14. Some integrations and adapters +have additional requirements. The Hermes Agent adapter does not support Python +3.14, and the Harbor integration requires Python 3.12 or later. -### Installing NeMo Fabric Runtime +### Choose an Installation -Install the NeMo Fabric Runtime: +The following table shows a representative subset of package expressions and +the components they install. The sections that follow describe the complete +installation alternatives. A **No** entry means that the expression does not +install that component; the component can already exist in the environment or +be managed separately. + +| Installation | Runtime | Adapter | Harness | NeMo Relay Python Package | +| --- | --- | --- | --- | --- | +| `nemo-fabric` | Yes | No | No | No | +| `nemo-fabric[relay]` | Yes | No | No | Yes | +| `nemo-fabric[hermes-agent,relay]` | Yes | Yes | Yes | Yes | +| `nemo-fabric-adapters-claude[harness]` | No | Yes | Yes | No | +| `nemo-fabric-adapters-claude[full]` | No | Yes | Yes | No | +| `nemo-fabric-adapters-deepagents[full]` | No | Yes | Yes | Yes | +| `nemo-fabric-adapters-hermes[relay]` | No | Yes | No | Yes | +| `nemo-fabric-adapters-claude` | No | Yes | No | No | + +An adapter package's `full` extra is scoped to the adapter environment. It +installs the supported harness and any Python Relay dependency, but it does not +install the NeMo Fabric runtime. For Claude and Codex, `full` is equivalent to +`harness` because their Relay integration requires an external executable. For +LangChain Deep Agents and Hermes Agent, `full` installs both the harness and the +NeMo Relay Python package. + +For Claude and Codex, no Python package extra installs the external +`nemo-relay` CLI required by Relay telemetry and `Runtime.invoke_stream()`. + +### Install the NeMo Fabric Runtime + +Install the NeMo Fabric runtime: ```bash -pip install "nemo-fabric[runtime]" +pip install nemo-fabric ``` -### Installing the NeMo Fabric Adapters +The `nemo-fabric` package installs the matching NeMo Fabric runtime +unconditionally. + +### Install a Complete Runtime and Harness -This command installs a NeMo Fabric adapter and its dependencies. Adapters -intentionally have minimal dependencies and belong in the same environment as -the agent harness. That environment can differ from the NeMo Fabric runtime -environment. +Use a `nemo-fabric` harness extra when the runtime, adapter, and harness run in +the same Python environment: -The following adapter extras are available: +```bash +pip install "nemo-fabric[claude]" +pip install "nemo-fabric[codex]" +pip install "nemo-fabric[deepagents]" +pip install "nemo-fabric[hermes-agent]" +``` -- `claude` -- `codex` -- `deepagents` -- `hermes` +Each `nemo-fabric` harness extra installs the corresponding adapter package +with its `harness` extra. You can combine independent `nemo-fabric` extras. For +example, the following command also installs Harbor and the NeMo Relay Python +package: ```bash -pip install "nemo-fabric[]" +pip install "nemo-fabric[claude,harbor,relay]" ``` -For example, to install the Hermes Agent adapter: +The `relay` extra does not install the external `nemo-relay` CLI that Claude and +Codex require for Relay-enabled runs. + +### Install an Adapter and Harness Without the Runtime + +Use an adapter package's `harness` extra when a different environment runs NeMo +Fabric: ```bash -pip install "nemo-fabric[hermes]" +pip install "nemo-fabric-adapters-claude[harness]" +pip install "nemo-fabric-adapters-codex[harness]" +pip install "nemo-fabric-adapters-deepagents[harness]" +pip install "nemo-fabric-adapters-hermes[harness]" +``` + +This installation mode keeps the runtime dependencies out of the adapter +environment. Set `ADAPTER_PYTHON` or `harness.settings.python` in the runtime +environment to the adapter environment's Python interpreter. A Python adapter +and its Python harness must use the same interpreter. Use matching NeMo Fabric +release versions for the runtime and adapter package unless a different pairing +has been explicitly validated. + +### Add an Adapter to an Existing Harness Environment + +Install an adapter package without an extra when the environment already +supplies and manages a compatible harness: + +```bash +pip install nemo-fabric-adapters-claude +pip install nemo-fabric-adapters-codex +pip install nemo-fabric-adapters-deepagents +pip install nemo-fabric-adapters-hermes +``` + +Bare adapter distributions install only adapter-owned dependencies. They do not +install the NeMo Fabric runtime or the harness. + +If the existing harness and runtime share an environment, install the runtime +and bare adapter together. The following example preserves the existing Codex +SDK instead of installing the adapter's supported SDK version: + +```bash +pip install nemo-fabric nemo-fabric-adapters-codex ``` ### Install NeMo Relay @@ -56,21 +128,37 @@ pip install "nemo-fabric[hermes]" [NeMo Relay](https://docs.nvidia.com/nemo/relay) integration occurs in two ways: -- [Python library](https://pypi.org/project/nemo-relay/) +- [Python package](https://pypi.org/project/nemo-relay/) - [NeMo Relay CLI](https://crates.io/crates/nemo-relay-cli) -The required integration depends on the agent harness chosen. Relay-enabled runs with -the Claude and Codex adapters require the [`nemo-relay` CLI](https://crates.io/crates/nemo-relay-cli). +The required integration depends on the agent harness. Relay-enabled runs with +the Claude and Codex adapters require the +[`nemo-relay` CLI](https://crates.io/crates/nemo-relay-cli). -#### NeMo Relay Python Library +#### NeMo Relay Python Package -The `relay` dependency extra installs a version of the NeMo Relay Python library known to be compatible with the -installed version of NeMo Fabric. +The root `relay` extra installs a version of the NeMo Relay Python package known +to be compatible with the installed version of NeMo Fabric: ```bash pip install "nemo-fabric[relay]" ``` +LangChain Deep Agents and Hermes Agent import the NeMo Relay Python package +directly. Their adapter packages provide `relay` and `full` extras: + +```bash +pip install "nemo-fabric-adapters-deepagents[relay]" +pip install "nemo-fabric-adapters-hermes[relay]" +pip install "nemo-fabric-adapters-deepagents[full]" +pip install "nemo-fabric-adapters-hermes[full]" +``` + +Use `relay` when the environment already manages the harness. Use `full` to +install the harness and Relay package together. Claude and Codex do not provide +a `relay` extra because their adapters launch the external CLI instead of +importing this Python package. + #### NeMo Relay CLI **Shell installation method (Linux and macOS):** @@ -91,11 +179,15 @@ irm https://raw.githubusercontent.com/NVIDIA/NeMo-Relay/main/install.ps1 | iex cargo binstall nemo-relay-cli ``` +After installation, ensure `nemo-relay` is on `PATH`. When Relay is enabled +with `FabricConfig.enable_relay(...)`, the Claude and Codex adapters start and +supervise the CLI gateway automatically. + ## Source Installation Method **Prerequisites:** - Rust and Cargo -- Python 3.11+ +- Python 3.11 through 3.14 - [uv](https://docs.astral.sh/uv/getting-started/installation/) - `just` 1.50.0+ diff --git a/docs/getting-started/quickstart.mdx b/docs/getting-started/quickstart.mdx index 3b69350c..ebd04698 100644 --- a/docs/getting-started/quickstart.mdx +++ b/docs/getting-started/quickstart.mdx @@ -9,14 +9,20 @@ This guide demonstrates how to install and run a simple agent using NeMo Fabric. ## Install NeMo Fabric -Create a Python virtual environment and install NeMo Fabric with Hermes Agent and the Hermes Agent adapter. +Using Python 3.11 through 3.13, create a virtual environment and install the +NeMo Fabric runtime, Hermes Agent adapter, and supported Hermes Agent +dependencies: + ```bash python -m venv .venv source .venv/bin/activate -pip install "nemo-fabric[hermes, hermes-agent]" +pip install "nemo-fabric[hermes-agent]" ``` -Refer to [the installation guide](https://github.com/NVIDIA/NeMo-Fabric#installation) for more details. +If the environment already manages Hermes Agent, install the runtime and bare +adapter with `pip install nemo-fabric nemo-fabric-adapters-hermes`. Refer to the +[installation guide](install.mdx) for separate adapter environments and the +other supported package combinations. ## Obtaining API Keys diff --git a/docs/integrations/harness/claude.mdx b/docs/integrations/harness/claude.mdx index 9a0ea198..84a64d07 100644 --- a/docs/integrations/harness/claude.mdx +++ b/docs/integrations/harness/claude.mdx @@ -10,17 +10,54 @@ Claude Code runtime. NeMo Fabric preserves Claude's native credential precedence forwards only supported operating-system, configuration, and authentication variables plus values explicitly configured in `environment.env`. -The adapter pins `claude-agent-sdk==0.2.120`. The SDK owns and selects its -compatible Claude Code runtime. +The adapter package's `harness` and `full` extras pin +`claude-agent-sdk==0.2.120`. Use the same version for an environment-managed +SDK. The SDK owns and selects its compatible Claude Code runtime. ## Install the Adapter -Install the adapter for Claude Code: +To install the NeMo Fabric runtime, Claude adapter, and supported Claude Agent +SDK in one environment: ```bash pip install "nemo-fabric[claude]" ``` +To install the adapter and supported Claude Agent SDK without the NeMo Fabric +runtime, use the adapter package's `harness` extra: + +```bash +pip install "nemo-fabric-adapters-claude[harness]" +``` + +The adapter package's `full` extra installs the same dependencies as `harness`; +it does not install the NeMo Fabric runtime. Claude Relay integration uses the +external `nemo-relay` CLI, not the Python `nemo-relay` package, so this adapter +does not provide a `relay` extra. Follow the +[NeMo Relay CLI installation procedure](../../getting-started/install.mdx#install-nemo-relay), +then ensure `nemo-relay` is on `PATH`. + +If the environment already manages a compatible Claude Agent SDK, install only +the adapter: + +```bash +pip install nemo-fabric-adapters-claude +``` + +The bare adapter package does not install the NeMo Fabric runtime or SDK. + +If the existing compatible Claude Agent SDK and NeMo Fabric runtime share an +environment, install the runtime and bare adapter together: + +```bash +pip install nemo-fabric nemo-fabric-adapters-claude +``` + +For separate environments, set `ADAPTER_PYTHON` or `harness.settings.python` in +the runtime environment to the adapter environment's Python interpreter. Use +matching NeMo Fabric release versions for the runtime and adapter package +unless a different pairing has been explicitly validated. + ## Configure the Adapter Select the Claude harness integration in `HarnessConfig`: diff --git a/docs/integrations/harness/codex.mdx b/docs/integrations/harness/codex.mdx index 0ab03177..681745c0 100644 --- a/docs/integrations/harness/codex.mdx +++ b/docs/integrations/harness/codex.mdx @@ -11,13 +11,49 @@ to the legacy Codex CLI adapter. ## Install the Adapter -Install the adapter and its Codex Python SDK dependencies in the environment -that runs the agent harness: +To install the NeMo Fabric runtime, Codex adapter, and supported Codex Python +SDK in one environment: ```bash pip install "nemo-fabric[codex]" ``` +To install the adapter and supported Codex SDK without the NeMo Fabric runtime, +use the adapter package's `harness` extra: + +```bash +pip install "nemo-fabric-adapters-codex[harness]" +``` + +The adapter package's `full` extra installs the same dependencies as `harness`; +it does not install the NeMo Fabric runtime. Codex Relay integration uses the +external `nemo-relay` CLI, not the Python `nemo-relay` package, so this adapter +does not provide a `relay` extra. Follow the +[NeMo Relay CLI installation procedure](../../getting-started/install.mdx#install-nemo-relay), +then ensure `nemo-relay` is on `PATH`. + +If the environment already manages a compatible Codex SDK, install only the +adapter: + +```bash +pip install nemo-fabric-adapters-codex +``` + +The bare adapter package does not install the NeMo Fabric runtime or SDK. Use +`openai-codex==0.144.4`, the constraint supported by this release. + +If the existing compatible Codex SDK and NeMo Fabric runtime share an +environment, install the runtime and bare adapter together: + +```bash +pip install nemo-fabric nemo-fabric-adapters-codex +``` + +For separate environments, set `ADAPTER_PYTHON` or `harness.settings.python` in +the runtime environment to the adapter environment's Python interpreter. Use +matching NeMo Fabric release versions for the runtime and adapter package +unless a different pairing has been explicitly validated. + ## Configure the Adapter Select the Codex harness integration in `HarnessConfig`: diff --git a/docs/integrations/harness/deepagents.mdx b/docs/integrations/harness/deepagents.mdx index be84fd85..e54c1150 100644 --- a/docs/integrations/harness/deepagents.mdx +++ b/docs/integrations/harness/deepagents.mdx @@ -13,13 +13,47 @@ telemetry. ## Install the Adapter -Install the adapter and its LangChain Deep Agents dependencies in the -environment that runs the agent harness: +To install the NeMo Fabric runtime, adapter, and supported LangChain Deep Agents +dependencies in one environment: ```bash pip install "nemo-fabric[deepagents]" ``` +To install the adapter and supported Deep Agents stack without the NeMo Fabric +runtime, use the adapter package's `harness` extra: + +```bash +pip install "nemo-fabric-adapters-deepagents[harness]" +``` + +The adapter package also provides `relay` and `full` extras. Use `relay` when +the environment already manages the Deep Agents stack. Use `full` to install +the stack and NeMo Relay Python package together. + +If the environment already manages a compatible Deep Agents stack, install only +the adapter: + +```bash +pip install nemo-fabric-adapters-deepagents +``` + +The bare adapter package does not install the NeMo Fabric runtime or harness. Use +`deepagents>=0.6.12,<0.7.0`, `langchain>=1.3,<2.0`, and +`langgraph>=1.2,<2.0`, the constraints supported by this release. + +If the existing compatible Deep Agents stack and NeMo Fabric runtime share an +environment, install the runtime and bare adapter together: + +```bash +pip install nemo-fabric nemo-fabric-adapters-deepagents +``` + +For separate environments, set `ADAPTER_PYTHON` or `harness.settings.python` in +the runtime environment to the adapter environment's Python interpreter. Use +matching NeMo Fabric release versions for the runtime and adapter package +unless a different pairing has been explicitly validated. + ## Configure the Adapter Select the LangChain Deep Agents harness integration in `HarnessConfig`: diff --git a/docs/integrations/harness/hermes.mdx b/docs/integrations/harness/hermes.mdx index 0a4564e2..695c6d5a 100644 --- a/docs/integrations/harness/hermes.mdx +++ b/docs/integrations/harness/hermes.mdx @@ -12,14 +12,47 @@ sessions, and telemetry. ## Install the Adapter -Install the adapter and a compatible Hermes Agent version in the environment -that runs the agent harness: +Hermes Agent and the adapter support Python 3.11 through 3.13. + +To install the NeMo Fabric runtime, Hermes Agent adapter, and supported Hermes +Agent dependencies in one environment: + +```bash +pip install "nemo-fabric[hermes-agent]" +``` + +To install the adapter and supported Hermes Agent without the NeMo Fabric +runtime, use the adapter package's `harness` extra: + +```bash +pip install "nemo-fabric-adapters-hermes[harness]" +``` + +The adapter package also provides `relay` and `full` extras. Use `relay` when +the environment already manages Hermes Agent. Use `full` to install Hermes +Agent and the NeMo Relay Python package together. + +If the environment already manages a compatible Hermes Agent, install only the +adapter: + +```bash +pip install nemo-fabric-adapters-hermes +``` + +The bare adapter package does not install the NeMo Fabric runtime or Hermes +Agent. Use `hermes-agent>=0.17.0`, the constraint supported by this release. + +If the existing compatible Hermes Agent and NeMo Fabric runtime share an +environment, install the runtime and bare adapter together: ```bash -pip install "nemo-fabric[hermes,hermes-agent]" +pip install nemo-fabric nemo-fabric-adapters-hermes ``` -Hermes Agent currently supports Python 3.11 through 3.13. +For separate environments, set `ADAPTER_PYTHON` or `harness.settings.python` in +the runtime environment to the adapter environment's Python interpreter. Use +matching NeMo Fabric release versions for the runtime and adapter package +unless a different pairing has been explicitly validated. ## Configure the Adapter diff --git a/docs/sdk/python.mdx b/docs/sdk/python.mdx index b8cc90c0..128d215f 100644 --- a/docs/sdk/python.mdx +++ b/docs/sdk/python.mdx @@ -506,7 +506,7 @@ Streaming has the following v0.1 constraints: Claude and Codex streaming use the NeMo Relay `nemo-relay` gateway CLI and require a stream-sink-capable release from `0.6.0` up to, but not including, `0.7.0`. Follow -the [NeMo Relay CLI installation instructions](../getting-started/install.mdx#nemo-relay-cli) +the [NeMo Relay CLI installation instructions](../getting-started/install.mdx#install-nemo-relay) to provision it. Hermes Agent and Deep Agents use their in-process NeMo Relay integrations. diff --git a/examples/harbor/README.md b/examples/harbor/README.md index ed0bd4fc..19399d3f 100644 --- a/examples/harbor/README.md +++ b/examples/harbor/README.md @@ -63,6 +63,22 @@ verifier run inside the isolated task container. Constructing the config does not read task paths; adapter and asset resolution is deferred to `Fabric.run()` with the task-local `base_dir`. +## Install the Host and Task Environments + +Use the following package requirements for the two-environment model. Pin the +host and task packages to the same NeMo Fabric release. These examples use +version `0.1.0`. + +| Environment | Required Dependencies | Purpose | +| --- | --- | --- | +| Harbor host | `nemo-fabric[harbor]==0.1.0` | Harbor CLI, `FabricAgent`, and typed `FabricConfig` construction | +| Claude task without Relay | `nemo-fabric[claude]==0.1.0` | NeMo Fabric runner, Claude adapter, and supported Claude harness | +| Claude task with Relay | `nemo-fabric[claude]==0.1.0` plus a NeMo Relay 0.6.x CLI on `PATH` | NeMo Fabric runner, Claude adapter and harness, and the adapter-managed Relay gateway and hooks | +| Hermes Agent task with Relay | `nemo-fabric[hermes-agent,relay]==0.1.0` | NeMo Fabric runner, Hermes Agent adapter and harness, and the NeMo Relay Python package | + +The `nemo-fabric` package installs the runtime. The `relay` extra installs the +NeMo Relay Python package, not the CLI required by Claude. + ## How Harbor Inputs Become FabricConfig `FabricAgent` starts with the selected adapter and Harbor task workspace, then @@ -99,9 +115,9 @@ and verify the relevant entry points: ```bash cd "$(git rev-parse --show-toplevel)" -uv sync --python 3.12 --extra runtime --extra harbor -uv run --extra runtime --extra harbor harbor --version -uv run --extra runtime --extra harbor python -c \ +uv sync --python 3.12 --extra harbor +uv run --extra harbor harbor --version +uv run --extra harbor python -c \ 'from nemo_fabric.integrations.harbor import FabricAgent; print(FabricAgent.import_path())' docker version docker compose version @@ -119,7 +135,7 @@ prints `/snap/bin/docker`, run this in every shell used for Harbor: ```bash mkdir -p "$HOME/harbor-tmp" export TMPDIR="$HOME/harbor-tmp" -uv run --extra runtime --extra harbor python -c \ +uv run --extra harbor python -c \ 'import tempfile; print(tempfile.gettempdir())' ``` diff --git a/examples/harbor/calculator/README.md b/examples/harbor/calculator/README.md index 6eee3d26..1de46c5e 100644 --- a/examples/harbor/calculator/README.md +++ b/examples/harbor/calculator/README.md @@ -58,7 +58,7 @@ This run checks Harbor setup, spec upload, sandbox-local SDK execution, workspace mutation, result download, and verification: ```bash -uv run --extra runtime --extra harbor harbor run \ +uv run --extra harbor harbor run \ --path "$TASK_DIR" \ --agent nemo_fabric.integrations.harbor:FabricAgent \ --ak fabric_adapter_id=demo.fabric.scripted \ @@ -78,7 +78,7 @@ Expected Harbor summary: one trial, zero exceptions, and mean reward `1.000`. ```bash : "${NVIDIA_API_KEY:?Export NVIDIA_API_KEY before running Hermes Agent}" -uv run --extra runtime --extra harbor --extra hermes-agent harbor run \ +uv run --extra harbor harbor run \ --path "$TASK_DIR" \ --agent nemo_fabric.integrations.harbor:FabricAgent \ --model nvidia/nemotron-3-nano-30b-a3b \ @@ -103,7 +103,7 @@ typed config. The API key is passed separately as a task credential. ```bash : "${NVIDIA_API_KEY:?Export NVIDIA_API_KEY before running Hermes Agent}" -uv run --extra runtime --extra harbor --extra hermes-agent --extra relay harbor run \ +uv run --extra harbor harbor run \ --path "$TASK_DIR" \ --agent nemo_fabric.integrations.harbor:FabricAgent \ --model nvidia/nemotron-3-nano-30b-a3b \ @@ -145,7 +145,7 @@ Claude authentication variables selected by the adapter; this command uses ```bash : "${ANTHROPIC_API_KEY:?Export ANTHROPIC_API_KEY before running Claude}" -uv run --extra runtime --extra harbor --extra claude harbor run \ +uv run --extra harbor harbor run \ --path "$TASK_DIR" \ --agent nemo_fabric.integrations.harbor:FabricAgent \ --model anthropic/claude-sonnet-4-5 \ @@ -174,7 +174,7 @@ NeMo Fabric result files use unique names in each trial's agent logs: ```bash find "$RUNS_DIR/fabric-smoke" -path '*/agent/fabric-result-*.json' -print -exec cat {} \; cat "$RUNS_DIR/fabric-smoke/result.json" -uv run --extra runtime --extra harbor harbor view "$RUNS_DIR" +uv run --extra harbor harbor view "$RUNS_DIR" ``` Check NeMo Fabric status, harness and adapter identity, runtime and invocation IDs, diff --git a/examples/harbor/calculator/task/environment/Dockerfile b/examples/harbor/calculator/task/environment/Dockerfile index 5f142351..83a88a96 100644 --- a/examples/harbor/calculator/task/environment/Dockerfile +++ b/examples/harbor/calculator/task/environment/Dockerfile @@ -19,7 +19,7 @@ RUN pip install --no-cache-dir \ -e /opt/nemo-fabric/adapters/common \ -e /opt/nemo-fabric/adapters/claude \ -e /opt/nemo-fabric/adapters/hermes \ - -e "/opt/nemo-fabric[harbor,hermes,hermes-agent,relay,runtime]" + -e "/opt/nemo-fabric[claude,hermes-agent,relay]" COPY calculator.py /app/calculator.py COPY fabric /opt/fabric-calculator diff --git a/examples/harbor/swebench/README.md b/examples/harbor/swebench/README.md index 729639ce..fae53a67 100644 --- a/examples/harbor/swebench/README.md +++ b/examples/harbor/swebench/README.md @@ -29,7 +29,7 @@ cd "$(git rev-parse --show-toplevel)" export FABRIC_AGENT='nemo_fabric.integrations.harbor:FabricAgent' export FABRIC_BUNDLE="$PWD/examples/harbor/swebench" -export FABRIC_PACKAGE='nemo-fabric[claude,harbor,hermes-agent,relay,runtime]==0.1.0a20260724' +export FABRIC_PACKAGE='nemo-fabric[claude,hermes-agent,relay]==0.1.0a20260724' export RUNS_DIR="$PWD/.tmp/harbor/fabric-swebench" curl -fsSL https://raw.githubusercontent.com/NVIDIA/NeMo-Relay/main/install.sh | @@ -51,7 +51,7 @@ Keep this shell open for the commands below. Run the credential-free installation gate before spending model tokens: ```bash -uv run --extra runtime --extra harbor harbor run \ +uv run --extra harbor harbor run \ --task swe-bench/django__django-13741 \ --agent "$FABRIC_AGENT" \ --ak fabric_adapter_id=nvidia.fabric.hermes \ @@ -72,7 +72,7 @@ The default Hermes Agent command uses NVIDIA's hosted API: ```bash : "${NVIDIA_API_KEY:?Export NVIDIA_API_KEY before running Hermes Agent}" -uv run --extra runtime --extra harbor harbor run \ +uv run --extra harbor harbor run \ --task swe-bench/django__django-13741 \ --agent "$FABRIC_AGENT" \ --model nvidia/nemotron-3-nano-30b-a3b \ @@ -100,7 +100,7 @@ harness switch reached Claude. ```bash : "${ANTHROPIC_API_KEY:?Export ANTHROPIC_API_KEY before running Claude}" -uv run --extra runtime --extra harbor harbor run \ +uv run --extra harbor harbor run \ --task swe-bench/django__django-13741 \ --agent "$FABRIC_AGENT" \ --model anthropic/claude-sonnet-4-5 \ @@ -138,7 +138,7 @@ For example, the complete skill variation is: ```bash : "${NVIDIA_API_KEY:?Export NVIDIA_API_KEY before running Hermes Agent}" -uv run --extra runtime --extra harbor harbor run \ +uv run --extra harbor harbor run \ --task swe-bench/django__django-13741 \ --agent "$FABRIC_AGENT" \ --model nvidia/nemotron-3-nano-30b-a3b \ @@ -176,7 +176,7 @@ means the proposed patch did not pass the task tests. export JOB_NAME=django-13741-hermes export RESULT_PATH="$RUNS_DIR/$JOB_NAME/result.json" -uv run --extra runtime --extra harbor python - "$RESULT_PATH" <<'PY' +uv run --extra harbor python - "$RESULT_PATH" <<'PY' import json import sys @@ -194,7 +194,7 @@ assert rewards, "Harbor did not record a verifier reward" print("verifier reward:", ", ".join(sorted(rewards))) PY -uv run --extra runtime --extra harbor harbor view "$RUNS_DIR/$JOB_NAME" +uv run --extra harbor harbor view "$RUNS_DIR/$JOB_NAME" ``` For a Relay-enabled job, select its job name and inspect the published evidence: @@ -204,10 +204,10 @@ export JOB_NAME=django-13741-hermes-relay find "$RUNS_DIR/$JOB_NAME" \ -path '*/agent/telemetry-validation.json' \ - -exec uv run --extra runtime --extra harbor python -m json.tool {} \; + -exec uv run --extra harbor python -m json.tool {} \; find "$RUNS_DIR/$JOB_NAME" \ -path '*/agent/trajectory.json' \ - -exec uv run --extra runtime --extra harbor python -m json.tool {} \; + -exec uv run --extra harbor python -m json.tool {} \; find "$RUNS_DIR/$JOB_NAME" \ \( -name '*.atof.jsonl' -o -name '*.atif.json' \) -print ``` @@ -228,7 +228,7 @@ five-task Hermes Agent shard with Relay enabled: ```bash : "${NVIDIA_API_KEY:?Export NVIDIA_API_KEY before running Hermes Agent}" -uv run --extra runtime --extra harbor harbor run \ +uv run --extra harbor harbor run \ --dataset swe-bench/swe-bench-verified \ --n-tasks 5 \ --agent "$FABRIC_AGENT" \ @@ -249,7 +249,7 @@ Spot-check progress and evidence without changing the running job: ```bash export JOB_NAME=swebench-verified-hermes-5 -uv run --extra runtime --extra harbor harbor view "$RUNS_DIR/$JOB_NAME" +uv run --extra harbor harbor view "$RUNS_DIR/$JOB_NAME" find "$RUNS_DIR/$JOB_NAME" -name result.json -print | head find "$RUNS_DIR/$JOB_NAME" \ -path '*/agent/telemetry-validation.json' -print | head @@ -260,7 +260,7 @@ summary. Resume an interrupted job from its recorded configuration: ```bash export JOB_NAME=swebench-verified-hermes-5 -uv run --extra runtime --extra harbor harbor job resume \ +uv run --extra harbor harbor job resume \ --job-path "$RUNS_DIR/$JOB_NAME" ``` diff --git a/justfile b/justfile index ca39dbc3..71685482 100644 --- a/justfile +++ b/justfile @@ -343,7 +343,7 @@ build-python: --group adapters \ "${editable_projects[@]}" else - uv sync --no-default-groups --group adapters --extra claude --extra runtime \ + uv sync --no-default-groups --group adapters \ --reinstall-package nemo-fabric \ --reinstall-package nemo-fabric-runtime fi @@ -414,7 +414,7 @@ test-python: #!/usr/bin/env bash set -euo pipefail if [[ "{{ no_uv }}" != "true" ]]; then - uv sync --group test --no-group dev --extra claude --extra codex --extra deepagents --extra harbor --extra hermes --extra hermes-agent --extra relay --extra runtime + uv sync --no-default-groups --group adapters --group adapter-tests --group test --extra harbor --extra relay fi uv run --no-sync pytest diff --git a/pypi.md b/pypi.md index 980f60e2..edee058a 100644 --- a/pypi.md +++ b/pypi.md @@ -31,24 +31,60 @@ It provides: ## Install +NeMo Fabric supports Python 3.11 through 3.14. Use Python 3.11 through 3.13 for +Hermes Agent; the Harbor integration requires Python 3.12 or later. + Install the core runtime and Python SDK: ```bash pip install nemo-fabric ``` -To use a supported agent harness, install its adapter extra: +To install the NeMo Fabric runtime, adapter, and supported harness in one +environment, choose one of the following `nemo-fabric` harness extras: ```bash pip install "nemo-fabric[claude]" pip install "nemo-fabric[codex]" pip install "nemo-fabric[deepagents]" -pip install "nemo-fabric[hermes]" +pip install "nemo-fabric[hermes-agent]" ``` -NeMo Fabric supports running an agent harness in a different virtual environment than the one used to run NeMo Fabric itself. This is useful for running agents that have conflicting dependencies with NeMo Fabric or other agents. +To install an adapter and its harness without the NeMo Fabric runtime, choose +one of the following adapter package `harness` extras: + +```bash +pip install "nemo-fabric-adapters-claude[harness]" +pip install "nemo-fabric-adapters-codex[harness]" +pip install "nemo-fabric-adapters-deepagents[harness]" +pip install "nemo-fabric-adapters-hermes[harness]" +``` -The adapter must be installed into the virtual environment that the harness is installed in. For this reason adapters intentionally have minimal dependencies. +Every adapter package also provides an adapter-scoped `full` extra, which does +not install the NeMo Fabric runtime. For Claude and Codex, `full` installs the +same dependencies as `harness`. For LangChain Deep Agents and Hermes Agent, +`full` also installs the NeMo Relay Python package. + +If the environment already manages a compatible harness, choose one of the +following bare adapter packages: + +```bash +pip install nemo-fabric-adapters-claude +pip install nemo-fabric-adapters-codex +pip install nemo-fabric-adapters-deepagents +pip install nemo-fabric-adapters-hermes +``` + +The adapter distribution contains only adapter-owned runtime dependencies. It +does not install the NeMo Fabric runtime. Select `harness` or `full` to install +the harness. If the runtime shares an environment with an existing compatible +harness, install `nemo-fabric` and the bare adapter package together. + +NeMo Fabric supports running an agent harness in a different virtual +environment from the NeMo Fabric runtime. This separation can isolate harnesses +that have conflicting dependencies. Use matching NeMo Fabric release versions +for the runtime and adapter package unless a different pairing has been +explicitly validated. ### Integrations @@ -64,16 +100,17 @@ pip install "nemo-fabric[harbor]" pip install "nemo-fabric[relay]" ``` -This installs a version of [NeMo Relay](https://docs.nvidia.com/nemo/relay) Python library known to be compatible with the installed version of NeMo Fabric. - -Some adapters, such as Claude and Codex, require the -[`nemo-relay` CLI](https://crates.io/crates/nemo-relay-cli) tool instead of the -NeMo Relay Python library. Refer to the -[NeMo Relay CLI](https://docs.nvidia.com/nemo/fabric/getting-started/install#nemo-relay-cli) install guide for instructions on installing the CLI tool. - -### Python Versions - -NeMo Fabric supports Python versions 3.11-3.14, however some of the integrations and adapters may have additional requirements. Specifically Hermes Agent doesn't support Python 3.14 yet, and the Harbor integration requires Python 3.12 or later. +This installs a version of the +[NeMo Relay Python package](https://docs.nvidia.com/nemo/relay) known to be +compatible with the installed version of NeMo Fabric. + +The LangChain Deep Agents and Hermes Agent adapter packages also provide +`relay` and `full` extras for environments that do not install `nemo-fabric`. +Claude and Codex require the +[`nemo-relay` CLI](https://crates.io/crates/nemo-relay-cli) instead of the NeMo +Relay Python package. They do not provide a `relay` extra. Refer to the +[NeMo Relay CLI](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-nemo-relay) +install guide for instructions on installing the CLI tool. ## Core Concepts diff --git a/pyproject.toml b/pyproject.toml index 13382287..2642d11b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,16 +37,16 @@ packages = [] [project.optional-dependencies] -codex = [ - "nemo-fabric-adapters-codex == 0.1.0", +claude = [ + "nemo-fabric-adapters-claude[harness] == 0.1.0", ] -claude = [ - "nemo-fabric-adapters-claude == 0.1.0", +codex = [ + "nemo-fabric-adapters-codex[harness] == 0.1.0", ] deepagents = [ - "nemo-fabric-adapters-deepagents == 0.1.0", + "nemo-fabric-adapters-deepagents[harness] == 0.1.0", ] harbor = [ @@ -54,22 +54,12 @@ harbor = [ "pyyaml>=6.0", ] -hermes = [ - "nemo-fabric-adapters-hermes == 0.1.0; python_version < '3.14'", -] - hermes-agent = [ - "nemo-fabric-adapters-hermes == 0.1.0; python_version < '3.14'", - "hermes-agent>=0.17.0; python_version < '3.14'", + "nemo-fabric-adapters-hermes[harness] == 0.1.0; python_version < '3.14'", ] relay = [ "nemo-relay>=0.6.0,<0.7", - "tomli-w~=1.2", # Needed by adapters to write relay config files -] - -runtime = [ - "nemo-fabric-runtime == 0.1.0", ] [dependency-groups] @@ -83,6 +73,13 @@ adapters = [ "nemo-fabric-adapters-hermes; python_version < '3.14'", ] +adapter-tests = [ + "nemo-fabric-adapters-claude[harness]", + "nemo-fabric-adapters-codex[harness]", + "nemo-fabric-adapters-deepagents[harness]", + "nemo-fabric-adapters-hermes[harness]; python_version < '3.14'", +] + dev = [ "ipython~=8.20", "pip-licenses>=5,<6", diff --git a/skills/integrations/consumer/nemo-fabric-integrate/SKILL.md b/skills/integrations/consumer/nemo-fabric-integrate/SKILL.md index c1c34edf..c8b3e771 100644 --- a/skills/integrations/consumer/nemo-fabric-integrate/SKILL.md +++ b/skills/integrations/consumer/nemo-fabric-integrate/SKILL.md @@ -44,13 +44,31 @@ that stay hidden behind this boundary. The consumer or its execution environment owns installation; NeMo Fabric validates runtime assumptions but never installs harnesses or credentials at run time. -- `uv pip install nemo-fabric[runtime]` (add the `harbor` extra for the Harbor integration). Refer to the +- NeMo Fabric supports Python 3.11 through 3.14. Use Python 3.11 through 3.13 + for Hermes Agent; the Harbor integration requires Python 3.12 or later. +- Install the runtime with `uv pip install nemo-fabric` (add the `harbor` extra + for the Harbor integration). Refer to the [installation guide](https://github.com/NVIDIA/NeMo-Fabric/blob/main/docs/getting-started/install.mdx). -- Select a harness adapter — the `adapter_id` set in `HarnessConfig`, for example - `nvidia.fabric.hermes` — and install its extra the same way, for example - `pip install "nemo-fabric[hermes]"` - (available extras: `hermes`, `codex`, `deepagents`, `claude`), plus the - corresponding harness binaries and dependencies. +- Select the harness adapter through `HarnessConfig.adapter_id`. To install the + NeMo Fabric runtime, adapter, and supported harness in one environment, use + `nemo-fabric[claude]`, `nemo-fabric[codex]`, + `nemo-fabric[deepagents]`, or `nemo-fabric[hermes-agent]`. +- In a separate adapter environment, install + `nemo-fabric-adapters-[harness]`. This installs the adapter and + supported harness dependencies without the NeMo Fabric runtime. Use `full` + instead when that adapter package provides package-installable optional + integrations. +- Point the runtime to a separate adapter environment with `ADAPTER_PYTHON` or + `harness.settings.python`. Use matching NeMo Fabric release versions for the + runtime and adapter package unless a different pairing has been explicitly + validated. +- If the adapter environment already manages a compatible harness, install the + bare `nemo-fabric-adapters-` distribution. Bare adapter + distributions contain only adapter-owned runtime dependencies. +- LangChain Deep Agents and Hermes Agent adapter packages provide `relay` and + include the NeMo Relay Python package in `full`. Claude and Codex use an + external `nemo-relay` CLI, so their adapter packages do not provide `relay`, + and `full` equals `harness`. - Provide model credentials through environment variables named by the config (`ModelConfig.api_key_env`), never as literals in code. - Confirm the native extension is importable; SDK calls raise diff --git a/tests/adapters/test_adapter_package_metadata.py b/tests/adapters/test_adapter_package_metadata.py new file mode 100644 index 00000000..430cc8ee --- /dev/null +++ b/tests/adapters/test_adapter_package_metadata.py @@ -0,0 +1,146 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Guard the published adapter dependency boundary.""" + +from __future__ import annotations + +import tomllib +from pathlib import Path + +import pytest + +ROOT_DIR = Path(__file__).resolve().parents[2] + + +def load_pyproject(path: str) -> dict: + return tomllib.loads( + (ROOT_DIR / path / "pyproject.toml").read_text(encoding="utf-8") + ) + + +PACKAGE_VERSION = load_pyproject("")["project"]["version"] +RUNTIME_DEPENDENCY = f"nemo-fabric-runtime == {PACKAGE_VERSION}" + +ADAPTER_EXTRAS = { + "claude": { + "path": "adapters/claude", + "root": f"nemo-fabric-adapters-claude[harness] == {PACKAGE_VERSION}", + "harness": ["claude-agent-sdk==0.2.120"], + }, + "codex": { + "path": "adapters/codex", + "root": f"nemo-fabric-adapters-codex[harness] == {PACKAGE_VERSION}", + "harness": ["openai-codex==0.144.4"], + }, + "deepagents": { + "path": "adapters/deepagents", + "root": f"nemo-fabric-adapters-deepagents[harness] == {PACKAGE_VERSION}", + "harness": [ + "deepagents>=0.6.12,<0.7.0", + "langchain>=1.3,<2.0", + "langgraph>=1.2,<2.0", + ], + "relay": ["nemo-relay>=0.6.0,<0.7"], + "full_relay": ["nemo-relay[deepagents]>=0.6.0,<0.7"], + }, + "hermes-agent": { + "path": "adapters/hermes", + "root": ( + f"nemo-fabric-adapters-hermes[harness] == {PACKAGE_VERSION}; " + "python_version < '3.14'" + ), + "harness": [ + "hermes-agent>=0.17.0; python_version < '3.14'" + ], + "relay": ["nemo-relay>=0.6.0,<0.7"], + }, +} + + +@pytest.mark.parametrize( + ("path", "expected"), + [ + ("adapters/common", []), + ( + "adapters/claude", + [ + f"nemo-fabric-adapters-common == {PACKAGE_VERSION}", + "tomli-w~=1.2", + ], + ), + ( + "adapters/codex", + [ + f"nemo-fabric-adapters-common == {PACKAGE_VERSION}", + "tomli-w~=1.2", + ], + ), + ( + "adapters/deepagents", + [ + f"nemo-fabric-adapters-common == {PACKAGE_VERSION}", + "langchain-mcp-adapters>=0.1,<0.3.0", + "langchain-openai>=0.3", + "langgraph-checkpoint-sqlite>=3.0,<4.0", + ], + ), + ( + "adapters/hermes", + [f"nemo-fabric-adapters-common == {PACKAGE_VERSION}"], + ), + ], +) +def test_adapter_runtime_dependencies(path: str, expected: list[str]): + project = load_pyproject(path)["project"] + assert project["version"] == PACKAGE_VERSION + assert sorted(project.get("dependencies", [])) == sorted(expected) + + +def test_adapter_test_dependency_group_matches_leaf_harnesses(): + manifest = load_pyproject("") + expected = [ + "nemo-fabric-adapters-claude[harness]", + "nemo-fabric-adapters-codex[harness]", + "nemo-fabric-adapters-deepagents[harness]", + "nemo-fabric-adapters-hermes[harness]; python_version < '3.14'", + ] + assert sorted(manifest["dependency-groups"]["adapter-tests"]) == sorted(expected) + assert "adapter-tests" not in manifest["tool"]["uv"]["default-groups"] + + +def test_root_package_installs_runtime_unconditionally(): + manifest = load_pyproject("") + project = manifest["project"] + + assert project["dependencies"] == [RUNTIME_DEPENDENCY] + assert manifest["tool"]["setuptools"]["packages"] == [] + + +def test_root_relay_extra_installs_only_relay(): + extras = load_pyproject("")["project"]["optional-dependencies"] + assert extras["relay"] == ["nemo-relay>=0.6.0,<0.7"] + + +@pytest.mark.parametrize("name", ADAPTER_EXTRAS) +def test_root_adapter_extras_delegate_to_leaf_harness_extras(name: str): + extras = load_pyproject("")["project"]["optional-dependencies"] + assert extras[name] == [ADAPTER_EXTRAS[name]["root"]] + assert set(extras) == set(ADAPTER_EXTRAS) | {"harbor", "relay"} + + +@pytest.mark.parametrize("name", ADAPTER_EXTRAS) +def test_leaf_adapter_extras_separate_harness_and_relay(name: str): + expected = ADAPTER_EXTRAS[name] + extras = load_pyproject(expected["path"])["project"]["optional-dependencies"] + relay = expected.get("relay", []) + full_relay = expected.get("full_relay", relay) + + assert extras["harness"] == expected["harness"] + assert sorted(extras["full"]) == sorted([*expected["harness"], *full_relay]) + + expected_names = {"harness", "full"} + if relay: + expected_names.add("relay") + assert extras["relay"] == relay + assert set(extras) == expected_names diff --git a/tests/adapters/test_hermes_config_builder.py b/tests/adapters/test_hermes_config_builder.py index 7c8bb9a5..ff80fc2b 100644 --- a/tests/adapters/test_hermes_config_builder.py +++ b/tests/adapters/test_hermes_config_builder.py @@ -3,7 +3,10 @@ """Dependency-free tests for Hermes configuration construction.""" +import builtins +import json import sys +from pathlib import Path import pytest @@ -36,3 +39,27 @@ def test_build_hermes_config_omits_unset_values_without_hermes_agent(): "default": "nvidia/test-model", } assert config["agent"] == {} + + +def test_write_hermes_config_round_trips_without_pyyaml( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, +): + real_import = builtins.__import__ + + def import_without_yaml(name: str, *args: object, **kwargs: object) -> object: + if name == "yaml": + raise ImportError("No module named yaml") + return real_import(name, *args, **kwargs) + + monkeypatch.setattr(builtins, "__import__", import_without_yaml) + payload = { + "config": { + "harness": {"settings": {}}, + "models": {"default": {"provider": "nvidia", "model": "nvidia/test-model"}}, + } + } + + config_path, config = adapter.write_hermes_config(payload, tmp_path / "hermes-home") + + assert json.loads(config_path.read_text(encoding="utf-8")) == config diff --git a/tests/integrations/test_harbor_runner.py b/tests/integrations/test_harbor_runner.py index e91ef926..91ac4237 100644 --- a/tests/integrations/test_harbor_runner.py +++ b/tests/integrations/test_harbor_runner.py @@ -3,6 +3,8 @@ import asyncio import json +import re +import tomllib from pathlib import Path from types import SimpleNamespace @@ -27,6 +29,13 @@ pytestmark = pytest.mark.usefixtures("requires_harbor") +def documented_root_extras(text: str) -> set[str]: + extras = set(re.findall(r"--extra\s+([a-z0-9-]+)", text)) + for selector in re.findall(r"nemo-fabric\[([^]]+)\]", text): + extras.update(extra.strip() for extra in selector.split(",")) + return extras + + def load_codex_adapter(): from nemo_fabric_adapters.codex import adapter @@ -255,7 +264,7 @@ def test_claude_calculator_run_uses_current_adapter_contract(): dockerfile = CALCULATOR_DOCKERFILE.read_text(encoding="utf-8") assert "-e /opt/nemo-fabric/adapters/claude" in dockerfile assert "-e /opt/nemo-fabric/adapters/hermes" in dockerfile - assert "nemo-fabric[harbor,hermes,hermes-agent,relay,runtime]" in dockerfile + assert "nemo-fabric[claude,hermes-agent,relay]" in dockerfile assert "@openai/codex" not in dockerfile @@ -284,13 +293,18 @@ def test_harbor_smoke_config_resolves_its_local_adapter(): def test_harbor_calculator_documents_explicit_cli_commands(): calculator = CALCULATOR_README.read_text(encoding="utf-8") + dockerfile = CALCULATOR_DOCKERFILE.read_text(encoding="utf-8") landing = INTEGRATION_README.read_text(encoding="utf-8") swebench = SWEBENCH_README.read_text(encoding="utf-8") + with (ROOT / "pyproject.toml").open("rb") as file: + declared_extras = set(tomllib.load(file)["project"]["optional-dependencies"]) assert "run.sh" not in calculator assert calculator.count(" harbor run \\") == 4 - assert landing.count("uv run --extra runtime --extra harbor harbor run") == 0 - assert swebench.count("uv run --extra runtime --extra harbor harbor run") == 5 + assert calculator.count("uv run --extra harbor harbor run \\") == 4 + assert "uv run --extra harbor --extra" not in calculator + assert landing.count("uv run --extra harbor harbor run") == 0 + assert swebench.count("uv run --extra harbor harbor run") == 5 assert "--agent-import-path" not in landing + calculator + swebench assert "fabric_config_path" not in calculator assert "fabric_config_path" not in landing @@ -304,12 +318,18 @@ def test_harbor_calculator_documents_explicit_cli_commands(): assert 'CALCULATOR_DIR="$PWD/examples/harbor/calculator"' in calculator assert "calculator/README.md" in landing assert "swebench/README.md" in landing + assert "nemo-fabric[harbor]==0.1.0" in landing + assert "nemo-fabric[claude]==0.1.0" in landing + assert "nemo-fabric[hermes-agent,relay]==0.1.0" in landing + assert documented_root_extras( + "\n".join((calculator, dockerfile, landing, swebench)) + ) <= declared_extras assert "fabric_adapter_id" in landing assert 'export TMPDIR="$HOME/harbor-tmp"' in landing assert "raw.githubusercontent.com/NVIDIA/NeMo-Relay/main/install.sh" in swebench assert ( "FABRIC_PACKAGE=" - "'nemo-fabric[claude,harbor,hermes-agent,relay,runtime]==0.1.0a20260724'" + "'nemo-fabric[claude,hermes-agent,relay]==0.1.0a20260724'" in swebench ) assert "PIP_FIND_LINKS" not in swebench diff --git a/tests/python/test_harbor_integration.py b/tests/python/test_harbor_integration.py index 34d2a09f..e5b86cde 100644 --- a/tests/python/test_harbor_integration.py +++ b/tests/python/test_harbor_integration.py @@ -356,7 +356,7 @@ async def test_harbor_structured_package_install_is_shell_safe(tmp_path: Path): agent = FabricAgent( logs_dir=tmp_path, fabric_adapter_id="nvidia.fabric.hermes", - fabric_package="nemo-fabric[codex,harbor,runtime]==0.1.0", + fabric_package="nemo-fabric[codex,harbor]==0.1.0", extra_env={ "NVIDIA_API_KEY": "test-key", "PIP_FIND_LINKS": "/tmp/nemo-fabric-config/wheelhouse", @@ -370,7 +370,7 @@ async def test_harbor_structured_package_install_is_shell_safe(tmp_path: Path): assert environment.commands[1] == ( "python3 -m venv /tmp/nemo-fabric-venv && " "/tmp/nemo-fabric-venv/bin/python -m pip install " - "--disable-pip-version-check 'nemo-fabric[codex,harbor,runtime]==0.1.0'" + "--disable-pip-version-check 'nemo-fabric[codex,harbor]==0.1.0'" ) assert environment.environments[1] == { "PIP_FIND_LINKS": "/tmp/nemo-fabric-config/wheelhouse", diff --git a/tests/python/test_readme_examples.py b/tests/python/test_readme_examples.py index a1f2d154..efe7bab6 100644 --- a/tests/python/test_readme_examples.py +++ b/tests/python/test_readme_examples.py @@ -18,7 +18,7 @@ "config = FabricConfig(", "[`01_quickstart.ipynb` notebook](examples/notebooks/01_quickstart.ipynb)", "[Python SDK guide](docs/sdk/python.mdx)", - "pip install \"nemo-fabric[runtime]\"", + "pip install nemo-fabric", ] DETAILED_SDK_SNIPPETS = ( diff --git a/uv.lock b/uv.lock index 99999ebe..76231c2a 100644 --- a/uv.lock +++ b/uv.lock @@ -2058,34 +2058,32 @@ dependencies = [ [package.optional-dependencies] claude = [ - { name = "nemo-fabric-adapters-claude" }, + { name = "nemo-fabric-adapters-claude", extra = ["harness"] }, ] codex = [ - { name = "nemo-fabric-adapters-codex" }, + { name = "nemo-fabric-adapters-codex", extra = ["harness"] }, ] deepagents = [ - { name = "nemo-fabric-adapters-deepagents" }, + { name = "nemo-fabric-adapters-deepagents", extra = ["harness"] }, ] harbor = [ { name = "harbor", marker = "python_full_version >= '3.12'" }, { name = "pyyaml" }, ] -hermes = [ - { name = "nemo-fabric-adapters-hermes", marker = "python_full_version < '3.14'" }, -] hermes-agent = [ - { name = "hermes-agent", marker = "python_full_version < '3.14'" }, - { name = "nemo-fabric-adapters-hermes", marker = "python_full_version < '3.14'" }, + { name = "nemo-fabric-adapters-hermes", extra = ["harness"], marker = "python_full_version < '3.14'" }, ] relay = [ { name = "nemo-relay" }, - { name = "tomli-w" }, -] -runtime = [ - { name = "nemo-fabric-runtime" }, ] [package.dev-dependencies] +adapter-tests = [ + { name = "nemo-fabric-adapters-claude", extra = ["harness"] }, + { name = "nemo-fabric-adapters-codex", extra = ["harness"] }, + { name = "nemo-fabric-adapters-deepagents", extra = ["harness"] }, + { name = "nemo-fabric-adapters-hermes", extra = ["harness"], marker = "python_full_version < '3.14'" }, +] adapters = [ { name = "nemo-fabric-adapters-claude" }, { name = "nemo-fabric-adapters-codex" }, @@ -2122,21 +2120,23 @@ test = [ [package.metadata] requires-dist = [ { name = "harbor", marker = "python_full_version >= '3.12' and extra == 'harbor'", specifier = ">=0.18,<0.19" }, - { name = "hermes-agent", marker = "python_full_version < '3.14' and extra == 'hermes-agent'", specifier = ">=0.17.0" }, - { name = "nemo-fabric-adapters-claude", marker = "extra == 'claude'", editable = "adapters/claude" }, - { name = "nemo-fabric-adapters-codex", marker = "extra == 'codex'", editable = "adapters/codex" }, - { name = "nemo-fabric-adapters-deepagents", marker = "extra == 'deepagents'", editable = "adapters/deepagents" }, - { name = "nemo-fabric-adapters-hermes", marker = "python_full_version < '3.14' and extra == 'hermes'", editable = "adapters/hermes" }, - { name = "nemo-fabric-adapters-hermes", marker = "python_full_version < '3.14' and extra == 'hermes-agent'", editable = "adapters/hermes" }, + { name = "nemo-fabric-adapters-claude", extras = ["harness"], marker = "extra == 'claude'", editable = "adapters/claude" }, + { name = "nemo-fabric-adapters-codex", extras = ["harness"], marker = "extra == 'codex'", editable = "adapters/codex" }, + { name = "nemo-fabric-adapters-deepagents", extras = ["harness"], marker = "extra == 'deepagents'", editable = "adapters/deepagents" }, + { name = "nemo-fabric-adapters-hermes", extras = ["harness"], marker = "python_full_version < '3.14' and extra == 'hermes-agent'", editable = "adapters/hermes" }, { name = "nemo-fabric-runtime", editable = "python" }, - { name = "nemo-fabric-runtime", marker = "extra == 'runtime'", editable = "python" }, { name = "nemo-relay", marker = "extra == 'relay'", specifier = ">=0.6.0,<0.7" }, { name = "pyyaml", marker = "extra == 'harbor'", specifier = ">=6.0" }, - { name = "tomli-w", marker = "extra == 'relay'", specifier = "~=1.2" }, ] -provides-extras = ["codex", "claude", "deepagents", "harbor", "hermes", "hermes-agent", "relay", "runtime"] +provides-extras = ["claude", "codex", "deepagents", "harbor", "hermes-agent", "relay"] [package.metadata.requires-dev] +adapter-tests = [ + { name = "nemo-fabric-adapters-claude", extras = ["harness"], editable = "adapters/claude" }, + { name = "nemo-fabric-adapters-codex", extras = ["harness"], editable = "adapters/codex" }, + { name = "nemo-fabric-adapters-deepagents", extras = ["harness"], editable = "adapters/deepagents" }, + { name = "nemo-fabric-adapters-hermes", extras = ["harness"], marker = "python_full_version < '3.14'", editable = "adapters/hermes" }, +] adapters = [ { name = "nemo-fabric-adapters-claude", editable = "adapters/claude" }, { name = "nemo-fabric-adapters-codex", editable = "adapters/codex" }, @@ -2175,17 +2175,23 @@ name = "nemo-fabric-adapters-claude" version = "0.1.0" source = { editable = "adapters/claude" } dependencies = [ - { name = "claude-agent-sdk" }, { name = "nemo-fabric-adapters-common" }, { name = "tomli-w" }, ] +[package.optional-dependencies] +harness = [ + { name = "claude-agent-sdk" }, +] + [package.metadata] requires-dist = [ - { name = "claude-agent-sdk", specifier = "==0.2.120" }, + { name = "claude-agent-sdk", marker = "extra == 'full'", specifier = "==0.2.120" }, + { name = "claude-agent-sdk", marker = "extra == 'harness'", specifier = "==0.2.120" }, { name = "nemo-fabric-adapters-common", editable = "adapters/common" }, { name = "tomli-w", specifier = "~=1.2" }, ] +provides-extras = ["harness", "full"] [[package]] name = "nemo-fabric-adapters-codex" @@ -2193,16 +2199,22 @@ version = "0.1.0" source = { editable = "adapters/codex" } dependencies = [ { name = "nemo-fabric-adapters-common" }, - { name = "openai-codex" }, { name = "tomli-w" }, ] +[package.optional-dependencies] +harness = [ + { name = "openai-codex" }, +] + [package.metadata] requires-dist = [ { name = "nemo-fabric-adapters-common", editable = "adapters/common" }, - { name = "openai-codex", specifier = "==0.144.4" }, + { name = "openai-codex", marker = "extra == 'full'", specifier = "==0.144.4" }, + { name = "openai-codex", marker = "extra == 'harness'", specifier = "==0.144.4" }, { name = "tomli-w", specifier = "~=1.2" }, ] +provides-extras = ["harness", "full"] [[package]] name = "nemo-fabric-adapters-common" @@ -2214,32 +2226,38 @@ name = "nemo-fabric-adapters-deepagents" version = "0.1.0" source = { editable = "adapters/deepagents" } dependencies = [ - { name = "deepagents" }, - { name = "langchain" }, { name = "langchain-mcp-adapters" }, { name = "langchain-openai" }, - { name = "langgraph" }, { name = "langgraph-checkpoint-sqlite" }, { name = "nemo-fabric-adapters-common" }, ] [package.optional-dependencies] +harness = [ + { name = "deepagents" }, + { name = "langchain" }, + { name = "langgraph" }, +] relay = [ - { name = "nemo-relay", extra = ["deepagents"] }, + { name = "nemo-relay" }, ] [package.metadata] requires-dist = [ - { name = "deepagents", specifier = ">=0.6.12,<0.7.0" }, - { name = "langchain", specifier = ">=1.3,<2.0" }, + { name = "deepagents", marker = "extra == 'full'", specifier = ">=0.6.12,<0.7.0" }, + { name = "deepagents", marker = "extra == 'harness'", specifier = ">=0.6.12,<0.7.0" }, + { name = "langchain", marker = "extra == 'full'", specifier = ">=1.3,<2.0" }, + { name = "langchain", marker = "extra == 'harness'", specifier = ">=1.3,<2.0" }, { name = "langchain-mcp-adapters", specifier = ">=0.1,<0.3.0" }, { name = "langchain-openai", specifier = ">=0.3" }, - { name = "langgraph", specifier = ">=1.2,<2.0" }, + { name = "langgraph", marker = "extra == 'full'", specifier = ">=1.2,<2.0" }, + { name = "langgraph", marker = "extra == 'harness'", specifier = ">=1.2,<2.0" }, { name = "langgraph-checkpoint-sqlite", specifier = ">=3.0,<4.0" }, { name = "nemo-fabric-adapters-common", editable = "adapters/common" }, - { name = "nemo-relay", extras = ["deepagents"], marker = "extra == 'relay'", specifier = ">=0.6.0,<0.7" }, + { name = "nemo-relay", marker = "extra == 'relay'", specifier = ">=0.6.0,<0.7" }, + { name = "nemo-relay", extras = ["deepagents"], marker = "extra == 'full'", specifier = ">=0.6.0,<0.7" }, ] -provides-extras = ["relay"] +provides-extras = ["harness", "relay", "full"] [[package]] name = "nemo-fabric-adapters-hermes" @@ -2247,14 +2265,22 @@ version = "0.1.0" source = { editable = "adapters/hermes" } dependencies = [ { name = "nemo-fabric-adapters-common", marker = "python_full_version < '3.14'" }, - { name = "pyyaml", marker = "python_full_version < '3.14'" }, +] + +[package.optional-dependencies] +harness = [ + { name = "hermes-agent", marker = "python_full_version < '3.14'" }, ] [package.metadata] requires-dist = [ + { name = "hermes-agent", marker = "python_full_version < '3.14' and extra == 'full'", specifier = ">=0.17.0" }, + { name = "hermes-agent", marker = "python_full_version < '3.14' and extra == 'harness'", specifier = ">=0.17.0" }, { name = "nemo-fabric-adapters-common", editable = "adapters/common" }, - { name = "pyyaml", specifier = ">=6.0" }, + { name = "nemo-relay", marker = "extra == 'full'", specifier = ">=0.6.0,<0.7" }, + { name = "nemo-relay", marker = "extra == 'relay'", specifier = ">=0.6.0,<0.7" }, ] +provides-extras = ["harness", "relay", "full"] [[package]] name = "nemo-fabric-runtime" @@ -2282,17 +2308,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cd/71/c438b9d746303ff7f270d99f13b250bf947cdac3e52de2a83fd132cbca0b/nemo_relay-0.6.0-cp311-abi3-win_arm64.whl", hash = "sha256:82fe132943399d89e6ec34dc28df0be7bbe41b84f6698c545928b8816b6010f6", size = 9034810, upload-time = "2026-07-22T20:07:57.467Z" }, ] -[package.optional-dependencies] -deepagents = [ - { name = "deepagents" }, - { name = "langchain" }, - { name = "langchain-anthropic" }, - { name = "langchain-core" }, - { name = "langgraph" }, - { name = "langgraph-checkpoint" }, - { name = "langsmith" }, -] - [[package]] name = "nodeenv" version = "1.10.0" From 55c5f744315219b780d17874b5282b8cbe069b76 Mon Sep 17 00:00:00 2001 From: David Gardner Date: Tue, 28 Jul 2026 16:57:06 -0700 Subject: [PATCH 02/15] Remove crates.io and pypi badges from the pypi readme Signed-off-by: David Gardner --- pypi.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/pypi.md b/pypi.md index edee058a..63dbec19 100644 --- a/pypi.md +++ b/pypi.md @@ -8,9 +8,6 @@ SPDX-License-Identifier: Apache-2.0 [![License](https://img.shields.io/github/license/NVIDIA/NeMo-Fabric)](https://github.com/NVIDIA/NeMo-Fabric/blob/main/LICENSE) [![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) [![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) -[![PyPI](https://img.shields.io/pypi/v/nemo-fabric?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-fabric/) -[![Crates.io](https://img.shields.io/crates/v/nemo-fabric-core?label=nemo-fabric-core&color=B7410E&logo=rust)](https://crates.io/crates/nemo-fabric-core) -[![Crates.io](https://img.shields.io/crates/v/nemo-fabric-cli?label=nemo-fabric-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-fabric-cli) NeMo Fabric gives applications one configurable, observable way to run applications across multiple agent harnesses. It standardizes configuration, lifecycle From ad2ab12989f4a908c77ff342ea34739b14d78625 Mon Sep 17 00:00:00 2001 From: David Gardner Date: Tue, 28 Jul 2026 16:59:02 -0700 Subject: [PATCH 03/15] Split readme into pypi files Signed-off-by: David Gardner --- adapters/claude/pypi.md | 242 +++++++++++++++++++++++++++++ adapters/claude/pyproject.toml | 2 +- adapters/codex/pypi.md | 150 ++++++++++++++++++ adapters/codex/pyproject.toml | 2 +- adapters/common/pypi.md | 60 +++++++ adapters/common/pyproject.toml | 2 +- adapters/deepagents/pypi.md | 216 +++++++++++++++++++++++++ adapters/deepagents/pyproject.toml | 2 +- adapters/hermes/pypi.md | 71 +++++++++ adapters/hermes/pyproject.toml | 2 +- 10 files changed, 744 insertions(+), 5 deletions(-) create mode 100644 adapters/claude/pypi.md create mode 100644 adapters/codex/pypi.md create mode 100644 adapters/common/pypi.md create mode 100644 adapters/deepagents/pypi.md create mode 100644 adapters/hermes/pypi.md diff --git a/adapters/claude/pypi.md b/adapters/claude/pypi.md new file mode 100644 index 00000000..345ff6da --- /dev/null +++ b/adapters/claude/pypi.md @@ -0,0 +1,242 @@ + + +# NVIDIA NeMo Fabric Claude Adapter + +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Fabric)](https://github.com/NVIDIA/NeMo-Fabric/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) + +The `nvidia.fabric.claude` adapter uses the official Claude Agent SDK for +Python behind NeMo Fabric's normalized invocation contract. The SDK is an +implementation detail; consumers select the Claude harness by adapter ID. + +The `harness` extra pins `claude-agent-sdk==0.2.120`; use the same version for an +environment-managed SDK. The SDK supplies a compatible Claude Code runtime. + +## Install + +The following table shows which components each installation provides: + +| Installation | Runtime | Adapter | Harness | NeMo Relay CLI | +| --- | --- | --- | --- | --- | +| `pip install "nemo-fabric[claude]"` | Yes | Yes | Yes | No | +| `pip install "nemo-fabric-adapters-claude[harness]"` | No | Yes | Yes | No | +| `pip install nemo-fabric-adapters-claude` | No | Yes | No | No | + +For split runtime and adapter environments, configure `ADAPTER_PYTHON` or +`harness.settings.python` and use matching NeMo Fabric release versions. Refer +to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-an-adapter-and-harness-without-the-runtime). + +The `full` extra is equivalent to `harness`. Relay is optional for ordinary +runs. Relay telemetry and `Runtime.invoke_stream()` require the external CLI +described under [Relay Observability](#relay-observability). + +## Authentication + +NeMo Fabric preserves Claude's native credential resolution. Use an existing Claude +Code login for local development, `ANTHROPIC_AUTH_TOKEN` for a gateway or proxy +bearer credential, `ANTHROPIC_API_KEY` for a static API credential, or Anthropic +Workload Identity Federation (WIF) for production and CI workloads that should +not store a long-lived API key. + +The native `anthropic` provider can use any Claude authentication mode above +without an explicit endpoint. For another provider name, configure both +`models..api_key_env` and `models..base_url`. The endpoint must +implement the Anthropic Messages protocol; the adapter maps the named +credential and endpoint into the environment expected by Claude Code. Provider +names identify configuration; the adapter does not maintain a provider +allowlist. The runtime-scoped mapping does not change the parent environment. + +The adapter forwards the Anthropic profile and federation environment variables +that Claude Code and the Claude Agent SDK consume. This includes +`ANTHROPIC_CONFIG_DIR`, `ANTHROPIC_PROFILE`, the direct federation identifiers, +and `ANTHROPIC_IDENTITY_TOKEN` or `ANTHROPIC_IDENTITY_TOKEN_FILE`. NeMo Fabric reads +selected environment values and forwards them to the Claude runtime, but it +does not persist or log them in configuration or artifacts. Authentication is +validated when the Claude runtime starts. + +Unset unused `ANTHROPIC_API_KEY` and `ANTHROPIC_AUTH_TOKEN` variables before +using WIF. Anthropic credential resolution treats an empty variable as selected, +so an empty API credential prevents fallback to a federation profile. + +Refer to the [Claude adapter authentication guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/integrations/harness/claude) +for mode selection, required WIF variables, and the Relay boundary. + +## Execution Model + +The Claude adapter implements NeMo Fabric's persistent local-host wire protocol. +`Fabric.start_runtime(...)` launches one adapter host, creates one +`ClaudeSDKClient`, and connects it once. Every `Runtime.invoke(...)` reuses that +client and its event loop; `Runtime.stop()` disconnects the client and exits the +host. `Fabric.run(...)` uses the same lifecycle around one invocation. + +One NeMo Fabric runtime maps to one live Claude session. The adapter records the +terminal Claude session ID under the NeMo Fabric artifact root for correlation, but +does not silently recreate a crashed host or replay an invocation. Start a new +NeMo Fabric runtime when the host or SDK connection becomes unusable. Runtime +hosting is adapter-declared; consumers do not configure a runtime strategy in +`FabricConfig` or `harness.settings`. + +## Configuration + +Configure portable capabilities through the normalized `FabricConfig` fields: + +- `models` selects the Claude model. The native `anthropic` provider retains + Claude authentication and endpoint discovery. Any other provider name must + configure an Anthropic Messages-compatible `base_url` and `api_key_env`. +- `instructions.system` supplies the Claude system instructions. +- `runtime.max_turns` sets the Claude turn limit. +- `runtime.timeout_seconds` sets the NeMo Fabric invocation deadline. +- `environment.workspace` sets the Claude working directory, and + `environment.env` supplies explicit harness-visible variables. +- `tools.enabled` selects Claude built-in tools. `None` preserves the Claude + default, while an empty list disables every tool. +- `tools.blocked` maps to Claude `disallowed_tools`. A pre-tool hook enforces + both lists across built-in, MCP, and plugin tools. +- `mcp` configures stdio, HTTP, streamable HTTP, or SSE servers. For stdio, + NeMo Fabric parses `url` as a command plus arguments. +- `skills.paths` names skill directories that contain `SKILL.md`. The adapter + stages these directories as a local Claude plugin for the runtime. + +Only Claude-specific controls belong in `harness.settings`: + +- `allowed_tools` and `permission_mode` +- `max_budget_usd` +- `setting_sources` (defaults to `[]` for deterministic isolation) + +The adapter filters the inherited environment before launching Claude Code. +It retains portable OS/config variables, the selected model's `api_key_env`, +and explicitly configured `environment.env` values. Raw Claude stderr is consumed +by the SDK and is not persisted as a NeMo Fabric artifact. + +## Relay Observability + +Relay requires a separately installed NeMo Relay 0.6.x CLI on `PATH`; the Python +`nemo-relay` package does not provide the executable. Follow the +[NeMo Relay installation instructions](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-nemo-relay). + +Enable Relay through the normalized NeMo Fabric configuration: + +```python +config.enable_relay( + project="fabric-review", + output_dir="./artifacts/relay", +) +``` + +For each Relay-enabled Claude runtime, NeMo Fabric starts one `nemo-relay` gateway, +waits for its health endpoint, and stops it with the runtime. NeMo Fabric passes the +gateway URL to the connected Claude Code process through `ANTHROPIC_BASE_URL` +and `NEMO_RELAY_GATEWAY_URL`, and passes the selected explicit model endpoint to +the gateway as its Anthropic upstream. It also stages a runtime-scoped Claude +plugin that forwards lifecycle hooks with `nemo-relay hook-forward claude`. +`Fabric.run(...)` starts the same runtime, invokes it once, and stops it, so the +gateway has the same lifecycle as that single invocation. + +The NeMo Fabric result includes `relay_runtime.gateway_config_path`, +`relay_runtime.gateway_log_path`, and the collected `relay_artifacts`. Relay +startup failures return a stable adapter error and retain the gateway log for +diagnosis. + +## Typed Configuration + +Build the agent configuration with the typed SDK models before invoking +NeMo Fabric: + +```python +from pathlib import Path + +from nemo_fabric import ( + EnvironmentConfig, + Fabric, + FabricConfig, + HarnessConfig, + InstructionConfig, + InstructionsConfig, + McpConfig, + McpServerConfig, + MetadataConfig, + ModelConfig, + RuntimeConfig, + SkillConfig, + ToolsConfig, +) + +base_dir = Path("/workspace/review-agent") +config = FabricConfig( + metadata=MetadataConfig(name="claude-review-agent"), + harness=HarnessConfig( + adapter_id="nvidia.fabric.claude", + resolution="preinstalled", + settings={ + "permission_mode": "dontAsk", + }, + ), + models={ + "default": ModelConfig( + provider="anthropic", + model="your-claude-model", + api_key_env="ANTHROPIC_API_KEY", + ) + }, + instructions=InstructionsConfig( + system=InstructionConfig( + content="Review changes for correctness and regressions.", + mode="replace", + ) + ), + runtime=RuntimeConfig( + artifacts="./artifacts", + timeout_seconds=600, + max_turns=8, + ), + environment=EnvironmentConfig(provider="local", workspace="."), + tools=ToolsConfig( + enabled=["Read", "Edit", "Bash"], + blocked=["WebFetch"], + ), + mcp=McpConfig( + servers={ + "repo": McpServerConfig( + transport="stdio", + url="repo-mcp --root .", + exposure="harness_native", + ) + } + ), + skills=SkillConfig(paths=["./skills/code-review"]), +) + +fabric = Fabric() +``` + +## Single Invocation + +```python +result = await fabric.run( + config, + base_dir=base_dir, + input="Inspect the repository", +) + +print(result.output["response"]) +print(result.output["session_id"]) +``` + +## Multi-Turn Runtime + +```python +async with await fabric.start_runtime(config, base_dir=base_dir) as runtime: + first = await runtime.invoke(input="Inspect the repository") + second = await runtime.invoke(input="Now review the latest patch") + +assert first.runtime_id == second.runtime_id +assert first.output["session_id"] == second.output["session_id"] +``` + +The runtime must remain on the same local host for its lifetime. A persisted +NeMo Fabric-to-Claude correlation record is not an attach token and cannot recover a +stopped or crashed local host. diff --git a/adapters/claude/pyproject.toml b/adapters/claude/pyproject.toml index 86874789..0cef58ed 100644 --- a/adapters/claude/pyproject.toml +++ b/adapters/claude/pyproject.toml @@ -22,7 +22,7 @@ classifiers = [ ] license = "Apache-2.0" license-files = ["LICENSE"] -readme = "README.md" +readme = "pypi.md" requires-python = ">=3.11" dependencies = [ "nemo-fabric-adapters-common == 0.1.0", diff --git a/adapters/codex/pypi.md b/adapters/codex/pypi.md new file mode 100644 index 00000000..6bc9e3e3 --- /dev/null +++ b/adapters/codex/pypi.md @@ -0,0 +1,150 @@ + + +# NVIDIA NeMo Fabric Codex Adapter + +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Fabric)](https://github.com/NVIDIA/NeMo-Fabric/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) + +The `nvidia.fabric.codex` adapter uses the official Codex Python SDK behind +NeMo Fabric's normalized invocation contract. It does not resolve or execute a +separately installed `codex` command. The SDK package owns its pinned +app-server runtime and typed JSON-RPC protocol. + +## Install + +The following table shows which components each installation provides: + +| Installation | Runtime | Adapter | Harness | NeMo Relay CLI | +| --- | --- | --- | --- | --- | +| `pip install "nemo-fabric[codex]"` | Yes | Yes | Yes | No | +| `pip install "nemo-fabric-adapters-codex[harness]"` | No | Yes | Yes | No | +| `pip install nemo-fabric-adapters-codex` | No | Yes | No | No | + +For an environment-managed SDK, use `openai-codex==0.144.4`. For split runtime +and adapter environments, configure `ADAPTER_PYTHON` or +`harness.settings.python` and use matching NeMo Fabric release versions. Refer +to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-an-adapter-and-harness-without-the-runtime). + +The `full` extra is equivalent to `harness`. Relay is optional for ordinary +runs. Relay telemetry and `Runtime.invoke_stream()` require the external CLI +described under [Relay Integration](#relay-integration). + +## Authentication + +NeMo Fabric reuses the authentication state that Codex stores under `CODEX_HOME` +(default: `~/.codex`). NeMo Fabric does not perform an interactive login, copy +credentials, or mutate the user's Codex configuration. + +Codex supports two OpenAI authentication modes: + +- **ChatGPT login:** Sign in through Codex with a ChatGPT plan. NeMo Fabric can then + run without `OPENAI_API_KEY` while that cached login remains valid. +- **API key login:** Provision the same Codex credential store with an OpenAI + API key. This mode uses OpenAI Platform billing rather than ChatGPT plan + credits. + +For a nondefault credential store, set `CODEX_HOME` before both login and the +NeMo Fabric invocation. Treat `CODEX_HOME/auth.json` as a secret when Codex uses +file-based credential storage. Refer to the +[Codex authentication documentation](https://developers.openai.com/codex/auth/) +for login, headless setup, and credential-storage options. + +The adapter forwards `OPENAI_API_KEY` and a selected model's `api_key_env` to +the SDK runtime. The current real-agent acceptance path validates an existing +Codex login; it does not yet claim a raw environment variable as a complete +login flow. + +The native `openai` provider retains Codex authentication and endpoint +discovery. For another provider name, configure both +`models..api_key_env` and `models..base_url`. The endpoint must +implement the OpenAI Responses protocol. The adapter defines a runtime-scoped +Codex model provider with that name and isolates its Codex state under the +NeMo Fabric artifact root, so execution does not depend on or modify a user's +Codex login. Provider names identify configuration; the adapter does not +maintain a provider allowlist. + +The adapter uses the Codex SDK, which installs and selects its matching +app-server runtime. NeMo Fabric does not declare the runtime package directly or +treat it as a user-installed command or adapter descriptor requirement. + +A `codex` command on `PATH` is not selected implicitly. + +## Execution Model + +Each NeMo Fabric runtime currently starts one local adapter host and retains one +`AsyncCodex` client and one Codex thread. The Codex starts and controls its +pinned local `codex app-server` subprocess over JSON-RPC. Ordered +`Runtime.invoke(...)` calls reuse that client and thread directly; the adapter +closes the SDK client and app-server transport during `Runtime.stop()`. Codex +owns the transcript; NeMo Fabric owns runtime-to-thread correlation, timeout, +cancellation, and cleanup. + +The result includes the SDK's typed terminal response, turn status, token +usage, timing, and completed thread items. It does not expose CLI commands, +return codes, stdout, or stderr. + +## Configuration + +Use normalized `FabricConfig` fields for portable configuration: + +- `models` selects the Codex model. The native `openai` provider retains Codex + authentication and endpoint discovery. Any other provider name must configure + a Responses-compatible `base_url` and `api_key_env`. +- `instructions.system` maps to Codex base instructions. +- `runtime.timeout_seconds` sets the NeMo Fabric invocation deadline. +- `environment.workspace` sets the working directory, and `environment.env` + supplies explicit harness-visible variables. +- `mcp` maps stdio, HTTP, and streamable HTTP servers into the Codex thread's + `mcp_servers` configuration. For stdio, NeMo Fabric parses `url` as a command plus + arguments. +- `skills.paths` names skill directories that contain `SKILL.md`. The adapter + registers each directory as a process-scoped Codex skill root so Codex can + select matching skills through its normal discovery behavior. +- `telemetry` enables native OpenTelemetry or NeMo Relay observability. + +The Codex adapter does not declare `tools.blocked` support. The current Codex +runtime has per-MCP-server tool filters, but it does not provide one complete +deny boundary for built-in, local, MCP, and hosted tools. NeMo Fabric therefore +routes normalized blocked-tool policy as unsupported instead of applying a +partial policy. + +Codex-specific controls belong in `harness.settings`: + +- `sandbox`: `read-only`, `workspace-write`, or `danger-full-access` +- `approval_mode`: `auto_review` or `deny_all` +- `developer_instructions` +- `personality`, `reasoning_effort`, and `service_tier` +- `output_schema` for SDK-native structured output +- `config_overrides` as dotted Codex configuration keys applied when the SDK + runtime starts, such as Codex-only MCP timeout or required-server options + +Set model selection and endpoints through `models`, system instructions through +`instructions.system`, the invocation deadline through +`runtime.timeout_seconds`, and the working directory and explicit environment +through `environment`. + +For `Fabric.start_runtime(...)`, the model provider, MCP configuration, skill +roots, and `config_overrides` are fixed when the runtime starts and cannot vary +between `Runtime.invoke(...)` calls. Start a new runtime to change them. +`Fabric.run(...)` starts the same runtime, invokes it once, and stops it, so the +same settings are scoped to that single invocation. + +The adapter filters the inherited environment. It retains portable OS and +Codex state variables, the selected model's `api_key_env`, and explicit +`environment.env` values while clearing unrelated parent-process secrets. + +## Relay Integration + +Relay requires a separately installed NeMo Relay 0.6.x CLI on `PATH`; the Python +`nemo-relay` package does not provide the executable. Follow the +[NeMo Relay installation instructions](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-nemo-relay). + +Enable Relay with `FabricConfig.enable_relay(...)`. The adapter starts the +installed `nemo-relay` CLI as a supervised sidecar; do not start the gateway +separately. +NeMo Fabric routes the selected Responses-compatible provider through the +gateway and passes its explicit `base_url` to Relay as the upstream endpoint. diff --git a/adapters/codex/pyproject.toml b/adapters/codex/pyproject.toml index bbdbc08f..35145320 100644 --- a/adapters/codex/pyproject.toml +++ b/adapters/codex/pyproject.toml @@ -22,7 +22,7 @@ classifiers = [ ] license = "Apache-2.0" license-files = ["LICENSE"] -readme = "README.md" +readme = "pypi.md" requires-python = ">=3.11" dependencies = [ "nemo-fabric-adapters-common == 0.1.0", diff --git a/adapters/common/pypi.md b/adapters/common/pypi.md new file mode 100644 index 00000000..f0ac1250 --- /dev/null +++ b/adapters/common/pypi.md @@ -0,0 +1,60 @@ + + +# NVIDIA NeMo Fabric Adapter Utilities + +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Fabric)](https://github.com/NVIDIA/NeMo-Fabric/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) + +`nemo-fabric-adapters-common` provides shared Python helpers for NeMo Fabric +adapter implementations. Adapter packages normally install +this package as a dependency. + +Install the package directly when developing an adapter: + +```bash +pip install nemo-fabric-adapters-common +``` + +Refer to the [NeMo Fabric documentation](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric) +for adapter and configuration guidance. Source code is available in the +[NVIDIA NeMo Fabric repository](https://github.com/NVIDIA/nemo-fabric/). + +## Persistent Local Hosts + +Every local Process or Python adapter implements the ordered persistent-host +wire protocol. Python adapters can use +`nemo_fabric_adapters.common.lifecycle`. Supply a factory that creates one +adapter-owned runtime with asynchronous `start`, `invoke`, and `stop` methods: + +```python +from nemo_fabric_adapters.common import lifecycle + + +class AdapterRuntime: + async def start(self, payload): + self.client = await connect_client(payload) + + async def invoke(self, payload): + return await self.client.run(payload["request"]["input"]) + + async def stop(self): + await self.client.close() + + +lifecycle.serve(AdapterRuntime) +``` + +NeMo Fabric calls the factory once per local host to create one runtime instance and +serializes invocations through that instance. The host keeps one event loop +alive for the complete lifecycle so SDK clients, compiled graphs, +checkpointers, and harness databases can remain live safely. NeMo Fabric sends the +resolved configuration and capability plan during `start`. Each subsequent +`invoke` wire payload contains only `runtime_context` and `request`, and the +helper passes that payload to `AdapterRuntime.invoke` unchanged. An adapter that +needs configuration during invocation retains it as runtime-owned state during +`start`. Adapter stdout is reserved for the protocol; diagnostics are redirected +to stderr. A host crash or protocol timeout terminates that runtime. diff --git a/adapters/common/pyproject.toml b/adapters/common/pyproject.toml index e428d1d4..c948544e 100644 --- a/adapters/common/pyproject.toml +++ b/adapters/common/pyproject.toml @@ -22,7 +22,7 @@ classifiers = [ ] license = "Apache-2.0" license-files = ["LICENSE"] -readme = "README.md" +readme = "pypi.md" requires-python = ">=3.11" [project.urls] diff --git a/adapters/deepagents/pypi.md b/adapters/deepagents/pypi.md new file mode 100644 index 00000000..819a21fc --- /dev/null +++ b/adapters/deepagents/pypi.md @@ -0,0 +1,216 @@ + + +# NVIDIA NeMo Fabric LangChain Deep Agents Adapter + +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Fabric)](https://github.com/NVIDIA/NeMo-Fabric/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) + +Runs a [LangChain Deep Agents](https://github.com/langchain-ai/deepagents) agent +inside NeMo Fabric's persistent Python adapter host. One started runtime retains the +compiled graph, checkpointer, and LangGraph thread across ordered invocations. + +## Install + +The following table shows which components each installation provides: + +| Installation | Runtime | Adapter | Harness | NeMo Relay Python Package | +| --- | --- | --- | --- | --- | +| `pip install "nemo-fabric[deepagents]"` | Yes | Yes | Yes | No | +| `pip install "nemo-fabric[deepagents,relay]"` | Yes | Yes | Yes | Yes | +| `pip install "nemo-fabric-adapters-deepagents[harness]"` | No | Yes | Yes | No | +| `pip install "nemo-fabric-adapters-deepagents[full]"` | No | Yes | Yes | Yes | +| `pip install "nemo-fabric-adapters-deepagents[relay]"` | No | Yes | No | Yes | +| `pip install nemo-fabric-adapters-deepagents` | No | Yes | No | No | + +For an environment-managed stack, use `deepagents>=0.6.12,<0.7.0`, +`langchain>=1.3,<2.0`, and `langgraph>=1.2,<2.0`. For split runtime and adapter +environments, configure `ADAPTER_PYTHON` or `harness.settings.python` and use +matching NeMo Fabric release versions. Refer to the +[installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-an-adapter-and-harness-without-the-runtime). + +## Model and Authentication + +The adapter builds a LangChain chat model from the selected NeMo Fabric model +role: `models.default`, or the sole configured role when `default` is absent. +The `openai`, `nvidia`, and `openai-compatible` providers use `ChatOpenAI`; +`nvidia` and `openai-compatible` require an explicit compatible `base_url`. +Any other provider is constructed through +`langchain.chat_models.init_chat_model`, so LangChain-supported backends do not +require adapter-specific branches. + +`models..api_key_env` names the environment variable holding the API key, +and defaults to `OPENAI_API_KEY` only for the native `openai` provider. Every +other provider must set `api_key_env` explicitly (a missing one is a normalized +configuration failure), so a key is never sent to the wrong endpoint. + +Because `models..api_key_env` is provider-specific, the adapter declares no +static env requirement; a runtime **preflight** verifies that the `deepagents` +package is importable and the configured credential is set. A failed preflight +fails runtime start with a stable lifecycle error. + +NeMo Fabric maps the following into the harness: + +- The selected `models` role supplies `model`, `provider`, `api_key_env`, + `base_url`, and `temperature`. +- `instructions.system` becomes the Deep Agents `system_prompt`. +- `runtime.timeout_seconds` sets the NeMo Fabric invocation deadline. +- `environment.workspace` roots the Deep Agents filesystem backend + (`FilesystemBackend(root_dir=..., virtual_mode=True)`). `virtual_mode` + confines the agent to the workspace: absolute paths and `..` cannot escape + `root_dir`. +- Routed `skills` (`native.skill_paths`) become the Deep Agents `skills` sources. +- Configured MCP servers are loaded as Deep Agents tools via + `langchain-mcp-adapters`. A misconfigured server (non-mapping, empty target, + unsupported transport) is a normalized configuration failure, not a silent drop. +- `tools.enabled` and `tools.blocked` are enforced by middleware across the full + tool surface: Deep Agents built-ins (including `task`), MCP tools, and + **delegated subagents** alike. Use Deep Agents-native tool names. +- `harness.settings.deepagents` forwards a small set of **documented, + JSON-serializable** `create_deep_agent` options (currently `subagents` and + `interrupt_on`). It is not a general Python-object escape hatch: the SDK config + round-trips through JSON and Rust planning, so `AgentMiddleware`, `BaseTool` + instances, and Python callables cannot cross the boundary. NeMo Fabric-owned + arguments (`model`, `tools`, `backend`, `skills`, `system_prompt`, `middleware`, + `checkpointer`) cannot be overridden through this passthrough, and an unknown or + unsupported key is an adapter configuration failure rather than a silently + dropped setting. + +### Subagents + +Deep Agents can delegate to subagents through its built-in `task` tool. Subagents +**inherit** the parent run's model, tools, skills, workspace, telemetry, and +permissions. When a normalized tools policy is configured, NeMo Fabric supplies +an explicitly gated `general-purpose` subagent and gates every declarative local +subagent, so delegation cannot broaden capabilities beyond the parent. Remote +and precompiled subagents are rejected in that case because their execution +cannot be governed by the local middleware. Independently configured subagent tools, skills, models, +MCP servers, middleware, or permissions are **not** exposed through the NeMo Fabric SDK +yet; a `subagents` definition here only carries JSON-shaped fields. + +The normalized result includes the final response, buffered messages and +per-step events, LangGraph thread id, token usage (and cost when the provider +reports it), and errors. Usage aggregates the current turn across the main agent +and any delegated subagents (streamed with `subgraphs=True`). Configuration and +preflight failures (a missing credential, an absent `deepagents` package, an +invalid MCP server, or a passthrough option) fail runtime start before an +invocation is accepted. + +## Runtime Lifecycle + +NeMo Fabric starts one local adapter host for every runtime. During runtime start, +the host compiles one Deep Agents graph, opens its async LangGraph checkpointer, +and creates one thread ID. Every invocation reuses those native objects; later +turns report `resumed` as `true`. The checkpointer lives under +the NeMo Fabric artifact root, scoped by runtime ID, and is closed during +runtime stop. The live host owns the thread identity, and LangGraph owns the +transcript. + +`Fabric.run(...)` is a convenience over that same lifecycle: it starts the +runtime, invokes it once, and stops it. It does not use a separate adapter +entrypoint or execution path. + +The `deepagents_config()` builder in `examples/code_review_agent` is the SDK +example. Run it from the CLI with +`python -m examples.code_review_agent --variant deepagents --input "..."`, or +drive the SDK directly: + +```python +from examples.code_review_agent import BASE_DIR, deepagents_config +from nemo_fabric import Fabric + +config = deepagents_config() +client = Fabric() + +# Single invocation through the standard runtime lifecycle. +result = await client.run( + config, base_dir=BASE_DIR, input="Review the workspace changes." +) +print(result["output"]["response"]) + +# Multi-turn: one started runtime keeps the LangGraph thread across turns. +async with await client.start_runtime(config, base_dir=BASE_DIR) as runtime: + await runtime.invoke(input="Remember the value 42.") + reply = await runtime.invoke(input="What value did I ask you to remember?") + # reply["output"]["resumed"] is True and the response recalls "42". + print(reply["output"]["resumed"], reply["output"]["response"]) +``` + +## Telemetry + +NeMo Relay is Deep Agents' single, SDK-native observability path — the adapter +does not expose gateway, CLI, or plugin launch modes for this harness. Relay is +**optional**: `nemo_relay` is imported lazily and only when telemetry is enabled, +so the core install stays Relay-neutral at import time. Relay telemetry and +`Runtime.invoke_stream()` require one of the installations in the table that +includes the NeMo Relay Python package. + +- **Relay** (`telemetry.providers.relay`): the SDK-native integration attaches + three complementary pieces around `create_deep_agent`, applied uniformly to + single-invocation, multi-turn, and subagent-enabled runs: + - `nemo_relay.integrations.deepagents.add_nemo_relay_integration(...)` injects + Deep Agents-aware **middleware** that routes model and tool calls through + Relay and emits skill/subagent configuration marks. + - The top-level invocation runs inside a + `nemo_relay.scope.scope("deepagents-request", nemo_relay.ScopeType.Agent)` + scope, so the whole NeMo Fabric turn is captured under one Agent scope. + - `NemoRelayDeepAgentsCallbackHandler()` is added to the LangGraph run config + (without dropping consumer-provided callbacks) to capture LangGraph scopes + and human-in-the-loop interrupt/resume marks. + + Runs emit ATOF/ATIF artifacts to the configured output directory, referenced in + the normalized result's `relay_artifacts` (and the `RunResult` `ArtifactManifest`). + OTel/OpenInference export is available through the relay plugin config; the + example provides `with_relay_otel(...)` and + `with_relay_openinference(...)` variants. +- **Native** (`telemetry.providers.native.config`): the provider config + OpenTelemetry/OpenInference exporter is applied and spans export directly to + the configured collector, without writing ATOF/ATIF relay artifacts. + +**Subagent boundary.** In-process, dictionary-style subagents are instrumented +with the same Relay middleware, so their model/tool calls appear under the same +trajectory. Remote and precompiled subagents (those defined with `graph_id` or +`url`) are **out of scope**: their internals execute in a separate runtime and +must be instrumented there with their own Relay integration. + +### Typed Relay configuration + +Enable Relay on a `FabricConfig` with the typed helpers — no gateway process or +CLI flags are involved: + +```python +from nemo_fabric import ( + RelayAtifConfig, + RelayAtofConfig, + RelayAtofFileSinkConfig, + RelayObservabilityConfig, +) +from examples.code_review_agent import deepagents_config + +# Start from a complete Deep Agents configuration, then enable typed Relay telemetry. +config = deepagents_config() +config.enable_relay( + output_dir="./artifacts/relay", + observability=RelayObservabilityConfig( + atof=RelayAtofConfig( + enabled=True, + sinks=[ + RelayAtofFileSinkConfig( + output_directory="./artifacts/relay", + filename="events.atof.jsonl", + mode="overwrite", + ) + ], + ), + atif=RelayAtifConfig( + enabled=True, + output_directory="./artifacts/relay", + filename_template="trajectory-{session_id}.atif.json", + agent_name="deepagents-agent", + ), + ), +) +``` diff --git a/adapters/deepagents/pyproject.toml b/adapters/deepagents/pyproject.toml index ed447d28..271350cd 100644 --- a/adapters/deepagents/pyproject.toml +++ b/adapters/deepagents/pyproject.toml @@ -22,7 +22,7 @@ classifiers = [ ] license = "Apache-2.0" license-files = ["LICENSE"] -readme = "README.md" +readme = "pypi.md" requires-python = ">=3.11" dependencies = [ "nemo-fabric-adapters-common == 0.1.0", diff --git a/adapters/hermes/pypi.md b/adapters/hermes/pypi.md new file mode 100644 index 00000000..00c2914e --- /dev/null +++ b/adapters/hermes/pypi.md @@ -0,0 +1,71 @@ + + +# NVIDIA NeMo Fabric Hermes Agent Adapter + +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Fabric)](https://github.com/NVIDIA/NeMo-Fabric/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) + +This adapter runs Hermes Agent through its Python SDK. + +## Install + +Hermes Agent and this adapter require Python 3.11 through 3.13. The following +table shows which components each installation provides: + +| Installation | Runtime | Adapter | Harness | NeMo Relay Python Package | +| --- | --- | --- | --- | --- | +| `pip install "nemo-fabric[hermes-agent]"` | Yes | Yes | Yes | No | +| `pip install "nemo-fabric[hermes-agent,relay]"` | Yes | Yes | Yes | Yes | +| `pip install "nemo-fabric-adapters-hermes[harness]"` | No | Yes | Yes | No | +| `pip install "nemo-fabric-adapters-hermes[full]"` | No | Yes | Yes | Yes | +| `pip install "nemo-fabric-adapters-hermes[relay]"` | No | Yes | No | Yes | +| `pip install nemo-fabric-adapters-hermes` | No | Yes | No | No | + +For an environment-managed harness, use `hermes-agent>=0.17.0`. For split +runtime and adapter environments, configure `ADAPTER_PYTHON` or +`harness.settings.python` and use matching NeMo Fabric release versions. Refer +to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-an-adapter-and-harness-without-the-runtime). + +Relay is optional for ordinary runs. Relay telemetry and +`Runtime.invoke_stream()` require one of the installations in the table that +includes the NeMo Relay Python package. + +## What It Maps + +The adapter receives a normalized payload from NeMo Fabric and materializes a native Hermes Agent configuration for: + +- selected model provider, model name, base URL, and temperature through + `models`; +- `instructions.system` and `runtime.max_turns`; +- workspace and explicit environment variables through `environment`; +- invocation timeout through `runtime.timeout_seconds`; +- NeMo Fabric skills as external skill directories for Hermes Agent; +- NeMo Fabric MCP servers as Hermes Agent MCP server config; +- `tools.enabled` and `tools.blocked` as Hermes-native toolset selection and + blocking policy; +- optional NeMo Relay telemetry plugin configuration. + +Tool selectors are Hermes toolset names because that is the native policy +surface Hermes exposes. Keep Hermes-specific controls such as +terminal timeout, reasoning configuration, and plugin configuration in +`harness.settings`. The adapter derives Hermes state from the NeMo Fabric +artifact root and creates a child under `runtimes/`, so invocations +in one NeMo Fabric runtime share state without sharing config or the session +database with another runtime. + +## Execution Model + +Each NeMo Fabric runtime starts one local adapter host, constructs one Hermes Agent +`AIAgent`, and opens one `SessionDB`. Ordered `Runtime.invoke(...)` calls reuse +those native objects and pass the prior turn's returned transcript back to +`run_conversation(...)`. Runtime stop calls the agent's idempotent `close()` +method, closes the session database, and releases the Relay plugin context when +enabled. + +Hermes Agent Relay telemetry is finalized after each NeMo Fabric invocation so its ATOF +and ATIF artifacts are complete when that invocation returns. This telemetry +boundary does not recreate the `AIAgent` or `SessionDB`. diff --git a/adapters/hermes/pyproject.toml b/adapters/hermes/pyproject.toml index 32c94ca8..c0569070 100644 --- a/adapters/hermes/pyproject.toml +++ b/adapters/hermes/pyproject.toml @@ -22,7 +22,7 @@ classifiers = [ ] license = "Apache-2.0" license-files = ["LICENSE"] -readme = "README.md" +readme = "pypi.md" # Hermes Agent does not currently support Python 3.14 or later. requires-python = ">=3.11,<3.14" dependencies = [ From c8f0c84bd1c426867360b4379d84e86a432b18d5 Mon Sep 17 00:00:00 2001 From: David Gardner Date: Tue, 28 Jul 2026 17:01:17 -0700 Subject: [PATCH 04/15] Split readme into pypi files Signed-off-by: David Gardner --- python/pypi.md | 25 +++++++++++++++++++++++++ python/pyproject.toml | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 python/pypi.md diff --git a/python/pypi.md b/python/pypi.md new file mode 100644 index 00000000..c8051b2c --- /dev/null +++ b/python/pypi.md @@ -0,0 +1,25 @@ + + +# NVIDIA NeMo Fabric Runtime + +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Fabric)](https://github.com/NVIDIA/NeMo-Fabric/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) + +`nemo-fabric-runtime` provides the Python SDK and native Rust bindings for +NVIDIA NeMo Fabric, a runtime execution layer for agents. + +```bash +pip install nemo-fabric-runtime +``` + +The package exposes the `nemo_fabric` Python module for typed agent +configuration, validation, run planning, runtime lifecycle management, +normalized results, artifacts, diagnostics, and telemetry references. + +Refer to the [NeMo Fabric documentation](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric) +for installation and usage guidance. Source code is available in the +[NVIDIA NeMo Fabric repository](https://github.com/NVIDIA/nemo-fabric/). diff --git a/python/pyproject.toml b/python/pyproject.toml index 4e952d05..bf98bc9d 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -19,7 +19,7 @@ classifiers = [ ] license = "Apache-2.0" license-files = ["LICENSE"] -readme = "README.md" +readme = "pypi.md" requires-python = ">=3.11" dependencies = [ "pydantic>=2.10,<3", From db7c134bf7815eef4d3848afc250b024c80db7b1 Mon Sep 17 00:00:00 2001 From: David Gardner Date: Wed, 29 Jul 2026 08:43:28 -0700 Subject: [PATCH 05/15] Add homepage and issues links, use exact url casing Signed-off-by: David Gardner --- pyproject.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2642d11b..a3bb5726 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,9 @@ dependencies = [ ] [project.urls] -Repository = "https://github.com/NVIDIA/nemo-fabric/" +Repository = "https://github.com/NVIDIA/NeMo-Fabric" +Homepage = "https://github.com/NVIDIA/NeMo-Fabric" +Issues = "https://github.com/NVIDIA/NeMo-Fabric/issues" Documentation = "https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric" [tool.setuptools] From 4dec2f8a34ea17f14c2e22acb2af871e6514ff03 Mon Sep 17 00:00:00 2001 From: David Gardner Date: Wed, 29 Jul 2026 09:20:12 -0700 Subject: [PATCH 06/15] Add homepage and issues links, use exact url casing Signed-off-by: David Gardner --- adapters/claude/pyproject.toml | 4 +++- adapters/codex/pyproject.toml | 4 +++- adapters/common/pyproject.toml | 4 +++- adapters/deepagents/pyproject.toml | 4 +++- adapters/hermes/pyproject.toml | 4 +++- python/pyproject.toml | 4 +++- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/adapters/claude/pyproject.toml b/adapters/claude/pyproject.toml index 0cef58ed..22bdceec 100644 --- a/adapters/claude/pyproject.toml +++ b/adapters/claude/pyproject.toml @@ -38,7 +38,9 @@ full = [ ] [project.urls] -Repository = "https://github.com/NVIDIA/nemo-fabric/" +Repository = "https://github.com/NVIDIA/NeMo-Fabric" +Homepage = "https://github.com/NVIDIA/NeMo-Fabric" +Issues = "https://github.com/NVIDIA/NeMo-Fabric/issues" Documentation = "https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric" [tool.setuptools.packages.find] diff --git a/adapters/codex/pyproject.toml b/adapters/codex/pyproject.toml index 35145320..5b2da91a 100644 --- a/adapters/codex/pyproject.toml +++ b/adapters/codex/pyproject.toml @@ -38,7 +38,9 @@ full = [ ] [project.urls] -Repository = "https://github.com/NVIDIA/nemo-fabric/" +Repository = "https://github.com/NVIDIA/NeMo-Fabric" +Homepage = "https://github.com/NVIDIA/NeMo-Fabric" +Issues = "https://github.com/NVIDIA/NeMo-Fabric/issues" Documentation = "https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric" [tool.setuptools.packages.find] diff --git a/adapters/common/pyproject.toml b/adapters/common/pyproject.toml index c948544e..7b644669 100644 --- a/adapters/common/pyproject.toml +++ b/adapters/common/pyproject.toml @@ -26,7 +26,9 @@ readme = "pypi.md" requires-python = ">=3.11" [project.urls] -Repository = "https://github.com/NVIDIA/nemo-fabric/" +Repository = "https://github.com/NVIDIA/NeMo-Fabric" +Homepage = "https://github.com/NVIDIA/NeMo-Fabric" +Issues = "https://github.com/NVIDIA/NeMo-Fabric/issues" Documentation = "https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric" [tool.setuptools.packages.find] diff --git a/adapters/deepagents/pyproject.toml b/adapters/deepagents/pyproject.toml index 271350cd..08c2c509 100644 --- a/adapters/deepagents/pyproject.toml +++ b/adapters/deepagents/pyproject.toml @@ -50,7 +50,9 @@ full = [ ] [project.urls] -Repository = "https://github.com/NVIDIA/nemo-fabric/" +Repository = "https://github.com/NVIDIA/NeMo-Fabric" +Homepage = "https://github.com/NVIDIA/NeMo-Fabric" +Issues = "https://github.com/NVIDIA/NeMo-Fabric/issues" Documentation = "https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric" [tool.setuptools.packages.find] diff --git a/adapters/hermes/pyproject.toml b/adapters/hermes/pyproject.toml index c0569070..5e4fd5fa 100644 --- a/adapters/hermes/pyproject.toml +++ b/adapters/hermes/pyproject.toml @@ -42,7 +42,9 @@ full = [ ] [project.urls] -Repository = "https://github.com/NVIDIA/nemo-fabric/" +Repository = "https://github.com/NVIDIA/NeMo-Fabric" +Homepage = "https://github.com/NVIDIA/NeMo-Fabric" +Issues = "https://github.com/NVIDIA/NeMo-Fabric/issues" Documentation = "https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric" [tool.setuptools.packages.find] diff --git a/python/pyproject.toml b/python/pyproject.toml index bf98bc9d..4f720e09 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -28,7 +28,9 @@ dependencies = [ dynamic = ["version"] [project.urls] -Repository = "https://github.com/NVIDIA/nemo-fabric/" +Repository = "https://github.com/NVIDIA/NeMo-Fabric" +Homepage = "https://github.com/NVIDIA/NeMo-Fabric" +Issues = "https://github.com/NVIDIA/NeMo-Fabric/issues" Documentation = "https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric" [tool.maturin] From 30a06e6c1162de6b044345bd49bead4d79b571d9 Mon Sep 17 00:00:00 2001 From: David Gardner Date: Wed, 29 Jul 2026 09:23:14 -0700 Subject: [PATCH 07/15] Cleanup install instructions Signed-off-by: David Gardner --- python/pypi.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/python/pypi.md b/python/pypi.md index c8051b2c..848c0ae3 100644 --- a/python/pypi.md +++ b/python/pypi.md @@ -12,6 +12,14 @@ SPDX-License-Identifier: Apache-2.0 `nemo-fabric-runtime` provides the Python SDK and native Rust bindings for NVIDIA NeMo Fabric, a runtime execution layer for agents. +Typically this is installed via the [`nemo-fabric`](https://pypi.org/project/nemo-fabric/) meta-package. + +```bash +pip install nemo-fabric +``` + +Is equivalent to: + ```bash pip install nemo-fabric-runtime ``` From 5f77c10e41b1f6b8a042157b38a9b005e892e804 Mon Sep 17 00:00:00 2001 From: David Gardner Date: Wed, 29 Jul 2026 09:28:26 -0700 Subject: [PATCH 08/15] Restore testing section, removing the testing.md Signed-off-by: David Gardner --- adapters/claude/README.md | 20 ++++++++++++++++++++ adapters/claude/testing.md | 23 ----------------------- 2 files changed, 20 insertions(+), 23 deletions(-) delete mode 100644 adapters/claude/testing.md diff --git a/adapters/claude/README.md b/adapters/claude/README.md index f13ad2f0..96d2ff94 100644 --- a/adapters/claude/README.md +++ b/adapters/claude/README.md @@ -237,3 +237,23 @@ assert first.output["session_id"] == second.output["session_id"] The runtime must remain on the same local host for its lifetime. A persisted NeMo Fabric-to-Claude correlation record is not an attach token and cannot recover a stopped or crashed local host. + + +## Testing + +The default suite uses deterministic mock Claude Code and Relay CLIs and +requires no credentials. Test a current `nemo-relay` CLI with the mock Claude +client, or run the live integrations on an authenticated developer host: + +```bash +FABRIC_NEMO_RELAY_COMMAND="$(command -v nemo-relay)" uv run --no-sync pytest tests/e2e/test_claude.py -q -k real_relay_gateway +RUN_FABRIC_CLAUDE_INTEGRATION=1 uv run --no-sync pytest tests/e2e/test_claude.py -q -k live +RUN_FABRIC_CLAUDE_RELAY_INTEGRATION=1 uv run --no-sync pytest tests/e2e/test_claude.py -q -k live_claude_relay +``` + +The first command uses the mock Claude client and does not require credentials. +Set `FABRIC_TEST_CLAUDE_MODEL` to override the default live-test model, +`claude-sonnet-4-5`. +The live Relay test applies the same semantic artifact contract as Codex: ATOF +must contain structured LLM requests and token usage, and ATIF must contain the +expected agent response. diff --git a/adapters/claude/testing.md b/adapters/claude/testing.md deleted file mode 100644 index 89e1ed0c..00000000 --- a/adapters/claude/testing.md +++ /dev/null @@ -1,23 +0,0 @@ - - -# Claude Adapter Tests - -The default suite uses deterministic mock Claude Code and Relay CLIs and -requires no credentials. Test a current `nemo-relay` CLI with the mock Claude -client, or run the live integrations on an authenticated developer host: - -```bash -FABRIC_NEMO_RELAY_COMMAND="$(command -v nemo-relay)" uv run --no-sync pytest tests/e2e/test_claude.py -q -k real_relay_gateway -RUN_FABRIC_CLAUDE_INTEGRATION=1 uv run --no-sync pytest tests/e2e/test_claude.py -q -k live -RUN_FABRIC_CLAUDE_RELAY_INTEGRATION=1 uv run --no-sync pytest tests/e2e/test_claude.py -q -k live_claude_relay -``` - -The first command uses the mock Claude client and does not require credentials. -Set `FABRIC_TEST_CLAUDE_MODEL` to override the default live-test model, -`claude-sonnet-4-5`. -The live Relay test applies the same semantic artifact contract as Codex: ATOF -must contain structured LLM requests and token usage, and ATIF must contain the -expected agent response. From 7b523dc657bae56e23b5dfcfc27e50e6a3976207 Mon Sep 17 00:00:00 2001 From: David Gardner Date: Wed, 29 Jul 2026 09:44:28 -0700 Subject: [PATCH 09/15] re-phrase Signed-off-by: David Gardner --- python/pypi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pypi.md b/python/pypi.md index 848c0ae3..41fbc053 100644 --- a/python/pypi.md +++ b/python/pypi.md @@ -12,7 +12,7 @@ SPDX-License-Identifier: Apache-2.0 `nemo-fabric-runtime` provides the Python SDK and native Rust bindings for NVIDIA NeMo Fabric, a runtime execution layer for agents. -Typically this is installed via the [`nemo-fabric`](https://pypi.org/project/nemo-fabric/) meta-package. +Typically this is installed using the [`nemo-fabric`](https://pypi.org/project/nemo-fabric/) meta-package. ```bash pip install nemo-fabric From fc8fe1b3a3020d6995884777c056a46ecb339293 Mon Sep 17 00:00:00 2001 From: David Gardner Date: Wed, 29 Jul 2026 09:44:46 -0700 Subject: [PATCH 10/15] Slim down to installation only Signed-off-by: David Gardner --- adapters/claude/pypi.md | 218 +--------------------------------------- 1 file changed, 4 insertions(+), 214 deletions(-) diff --git a/adapters/claude/pypi.md b/adapters/claude/pypi.md index 345ff6da..9b274a49 100644 --- a/adapters/claude/pypi.md +++ b/adapters/claude/pypi.md @@ -9,16 +9,13 @@ SPDX-License-Identifier: Apache-2.0 [![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) [![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) -The `nvidia.fabric.claude` adapter uses the official Claude Agent SDK for -Python behind NeMo Fabric's normalized invocation contract. The SDK is an -implementation detail; consumers select the Claude harness by adapter ID. +Provides a NeMo Fabric adapter for use with [Claude Code](https://claude.com/). -The `harness` extra pins `claude-agent-sdk==0.2.120`; use the same version for an -environment-managed SDK. The SDK supplies a compatible Claude Code runtime. +The `nvidia.fabric.claude` adapter uses the official [Claude Agent SDK](https://code.claude.com/docs/en/agent-sdk)using a NeMo Fabric normalized invocation contract. ## Install -The following table shows which components each installation provides: +Installation can be performed using the `nemo-fabric` meta-package with the `claude` extra, or by installing the adapter and harness packages separately. The following table shows which components each installation provides: | Installation | Runtime | Adapter | Harness | NeMo Relay CLI | | --- | --- | --- | --- | --- | @@ -31,212 +28,5 @@ For split runtime and adapter environments, configure `ADAPTER_PYTHON` or to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-an-adapter-and-harness-without-the-runtime). The `full` extra is equivalent to `harness`. Relay is optional for ordinary -runs. Relay telemetry and `Runtime.invoke_stream()` require the external CLI -described under [Relay Observability](#relay-observability). +runs. Relay telemetry and `Runtime.invoke_stream()` require the `nemo-relay` CLI tool to be installed, refer to the [Relay installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#nemo-relay-cli). -## Authentication - -NeMo Fabric preserves Claude's native credential resolution. Use an existing Claude -Code login for local development, `ANTHROPIC_AUTH_TOKEN` for a gateway or proxy -bearer credential, `ANTHROPIC_API_KEY` for a static API credential, or Anthropic -Workload Identity Federation (WIF) for production and CI workloads that should -not store a long-lived API key. - -The native `anthropic` provider can use any Claude authentication mode above -without an explicit endpoint. For another provider name, configure both -`models..api_key_env` and `models..base_url`. The endpoint must -implement the Anthropic Messages protocol; the adapter maps the named -credential and endpoint into the environment expected by Claude Code. Provider -names identify configuration; the adapter does not maintain a provider -allowlist. The runtime-scoped mapping does not change the parent environment. - -The adapter forwards the Anthropic profile and federation environment variables -that Claude Code and the Claude Agent SDK consume. This includes -`ANTHROPIC_CONFIG_DIR`, `ANTHROPIC_PROFILE`, the direct federation identifiers, -and `ANTHROPIC_IDENTITY_TOKEN` or `ANTHROPIC_IDENTITY_TOKEN_FILE`. NeMo Fabric reads -selected environment values and forwards them to the Claude runtime, but it -does not persist or log them in configuration or artifacts. Authentication is -validated when the Claude runtime starts. - -Unset unused `ANTHROPIC_API_KEY` and `ANTHROPIC_AUTH_TOKEN` variables before -using WIF. Anthropic credential resolution treats an empty variable as selected, -so an empty API credential prevents fallback to a federation profile. - -Refer to the [Claude adapter authentication guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/integrations/harness/claude) -for mode selection, required WIF variables, and the Relay boundary. - -## Execution Model - -The Claude adapter implements NeMo Fabric's persistent local-host wire protocol. -`Fabric.start_runtime(...)` launches one adapter host, creates one -`ClaudeSDKClient`, and connects it once. Every `Runtime.invoke(...)` reuses that -client and its event loop; `Runtime.stop()` disconnects the client and exits the -host. `Fabric.run(...)` uses the same lifecycle around one invocation. - -One NeMo Fabric runtime maps to one live Claude session. The adapter records the -terminal Claude session ID under the NeMo Fabric artifact root for correlation, but -does not silently recreate a crashed host or replay an invocation. Start a new -NeMo Fabric runtime when the host or SDK connection becomes unusable. Runtime -hosting is adapter-declared; consumers do not configure a runtime strategy in -`FabricConfig` or `harness.settings`. - -## Configuration - -Configure portable capabilities through the normalized `FabricConfig` fields: - -- `models` selects the Claude model. The native `anthropic` provider retains - Claude authentication and endpoint discovery. Any other provider name must - configure an Anthropic Messages-compatible `base_url` and `api_key_env`. -- `instructions.system` supplies the Claude system instructions. -- `runtime.max_turns` sets the Claude turn limit. -- `runtime.timeout_seconds` sets the NeMo Fabric invocation deadline. -- `environment.workspace` sets the Claude working directory, and - `environment.env` supplies explicit harness-visible variables. -- `tools.enabled` selects Claude built-in tools. `None` preserves the Claude - default, while an empty list disables every tool. -- `tools.blocked` maps to Claude `disallowed_tools`. A pre-tool hook enforces - both lists across built-in, MCP, and plugin tools. -- `mcp` configures stdio, HTTP, streamable HTTP, or SSE servers. For stdio, - NeMo Fabric parses `url` as a command plus arguments. -- `skills.paths` names skill directories that contain `SKILL.md`. The adapter - stages these directories as a local Claude plugin for the runtime. - -Only Claude-specific controls belong in `harness.settings`: - -- `allowed_tools` and `permission_mode` -- `max_budget_usd` -- `setting_sources` (defaults to `[]` for deterministic isolation) - -The adapter filters the inherited environment before launching Claude Code. -It retains portable OS/config variables, the selected model's `api_key_env`, -and explicitly configured `environment.env` values. Raw Claude stderr is consumed -by the SDK and is not persisted as a NeMo Fabric artifact. - -## Relay Observability - -Relay requires a separately installed NeMo Relay 0.6.x CLI on `PATH`; the Python -`nemo-relay` package does not provide the executable. Follow the -[NeMo Relay installation instructions](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-nemo-relay). - -Enable Relay through the normalized NeMo Fabric configuration: - -```python -config.enable_relay( - project="fabric-review", - output_dir="./artifacts/relay", -) -``` - -For each Relay-enabled Claude runtime, NeMo Fabric starts one `nemo-relay` gateway, -waits for its health endpoint, and stops it with the runtime. NeMo Fabric passes the -gateway URL to the connected Claude Code process through `ANTHROPIC_BASE_URL` -and `NEMO_RELAY_GATEWAY_URL`, and passes the selected explicit model endpoint to -the gateway as its Anthropic upstream. It also stages a runtime-scoped Claude -plugin that forwards lifecycle hooks with `nemo-relay hook-forward claude`. -`Fabric.run(...)` starts the same runtime, invokes it once, and stops it, so the -gateway has the same lifecycle as that single invocation. - -The NeMo Fabric result includes `relay_runtime.gateway_config_path`, -`relay_runtime.gateway_log_path`, and the collected `relay_artifacts`. Relay -startup failures return a stable adapter error and retain the gateway log for -diagnosis. - -## Typed Configuration - -Build the agent configuration with the typed SDK models before invoking -NeMo Fabric: - -```python -from pathlib import Path - -from nemo_fabric import ( - EnvironmentConfig, - Fabric, - FabricConfig, - HarnessConfig, - InstructionConfig, - InstructionsConfig, - McpConfig, - McpServerConfig, - MetadataConfig, - ModelConfig, - RuntimeConfig, - SkillConfig, - ToolsConfig, -) - -base_dir = Path("/workspace/review-agent") -config = FabricConfig( - metadata=MetadataConfig(name="claude-review-agent"), - harness=HarnessConfig( - adapter_id="nvidia.fabric.claude", - resolution="preinstalled", - settings={ - "permission_mode": "dontAsk", - }, - ), - models={ - "default": ModelConfig( - provider="anthropic", - model="your-claude-model", - api_key_env="ANTHROPIC_API_KEY", - ) - }, - instructions=InstructionsConfig( - system=InstructionConfig( - content="Review changes for correctness and regressions.", - mode="replace", - ) - ), - runtime=RuntimeConfig( - artifacts="./artifacts", - timeout_seconds=600, - max_turns=8, - ), - environment=EnvironmentConfig(provider="local", workspace="."), - tools=ToolsConfig( - enabled=["Read", "Edit", "Bash"], - blocked=["WebFetch"], - ), - mcp=McpConfig( - servers={ - "repo": McpServerConfig( - transport="stdio", - url="repo-mcp --root .", - exposure="harness_native", - ) - } - ), - skills=SkillConfig(paths=["./skills/code-review"]), -) - -fabric = Fabric() -``` - -## Single Invocation - -```python -result = await fabric.run( - config, - base_dir=base_dir, - input="Inspect the repository", -) - -print(result.output["response"]) -print(result.output["session_id"]) -``` - -## Multi-Turn Runtime - -```python -async with await fabric.start_runtime(config, base_dir=base_dir) as runtime: - first = await runtime.invoke(input="Inspect the repository") - second = await runtime.invoke(input="Now review the latest patch") - -assert first.runtime_id == second.runtime_id -assert first.output["session_id"] == second.output["session_id"] -``` - -The runtime must remain on the same local host for its lifetime. A persisted -NeMo Fabric-to-Claude correlation record is not an attach token and cannot recover a -stopped or crashed local host. From ba74096d0481da61f0835f1e7e4f144dff24e505 Mon Sep 17 00:00:00 2001 From: David Gardner Date: Wed, 29 Jul 2026 10:21:53 -0700 Subject: [PATCH 11/15] Trim down the pypi readme files to just installation instructions Signed-off-by: David Gardner --- adapters/claude/pypi.md | 12 +-- adapters/codex/pypi.md | 133 +----------------------- adapters/common/pypi.md | 46 ++------- adapters/deepagents/pypi.md | 197 ++---------------------------------- adapters/hermes/pypi.md | 52 ++-------- python/pypi.md | 2 +- 6 files changed, 29 insertions(+), 413 deletions(-) diff --git a/adapters/claude/pypi.md b/adapters/claude/pypi.md index 9b274a49..02534faa 100644 --- a/adapters/claude/pypi.md +++ b/adapters/claude/pypi.md @@ -11,11 +11,9 @@ SPDX-License-Identifier: Apache-2.0 Provides a NeMo Fabric adapter for use with [Claude Code](https://claude.com/). -The `nvidia.fabric.claude` adapter uses the official [Claude Agent SDK](https://code.claude.com/docs/en/agent-sdk)using a NeMo Fabric normalized invocation contract. - ## Install -Installation can be performed using the `nemo-fabric` meta-package with the `claude` extra, or by installing the adapter and harness packages separately. The following table shows which components each installation provides: +Installation can be performed using the `nemo-fabric` meta package with the `claude` extra, or by installing the adapter and harness packages separately. The following table shows which components each installation provides: | Installation | Runtime | Adapter | Harness | NeMo Relay CLI | | --- | --- | --- | --- | --- | @@ -23,10 +21,8 @@ Installation can be performed using the `nemo-fabric` meta-package with the `cla | `pip install "nemo-fabric-adapters-claude[harness]"` | No | Yes | Yes | No | | `pip install nemo-fabric-adapters-claude` | No | Yes | No | No | -For split runtime and adapter environments, configure `ADAPTER_PYTHON` or -`harness.settings.python` and use matching NeMo Fabric release versions. Refer -to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-an-adapter-and-harness-without-the-runtime). - The `full` extra is equivalent to `harness`. Relay is optional for ordinary -runs. Relay telemetry and `Runtime.invoke_stream()` require the `nemo-relay` CLI tool to be installed, refer to the [Relay installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#nemo-relay-cli). +runs. NeMo Relay telemetry and streaming require the `nemo-relay` CLI tool to be installed, refer to the [NeMo Relay installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#nemo-relay-cli). + +Refer to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install) for more details. diff --git a/adapters/codex/pypi.md b/adapters/codex/pypi.md index 6bc9e3e3..d928ae4b 100644 --- a/adapters/codex/pypi.md +++ b/adapters/codex/pypi.md @@ -9,14 +9,11 @@ SPDX-License-Identifier: Apache-2.0 [![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) [![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) -The `nvidia.fabric.codex` adapter uses the official Codex Python SDK behind -NeMo Fabric's normalized invocation contract. It does not resolve or execute a -separately installed `codex` command. The SDK package owns its pinned -app-server runtime and typed JSON-RPC protocol. +Provides a NeMo Fabric adapter for use with [Codex](https://openai.com/codex/). ## Install -The following table shows which components each installation provides: +Installation can be performed using the `nemo-fabric` meta package with the `codex` extra, or by installing the adapter and harness packages separately. The following table shows which components each installation provides: | Installation | Runtime | Adapter | Harness | NeMo Relay CLI | | --- | --- | --- | --- | --- | @@ -24,127 +21,7 @@ The following table shows which components each installation provides: | `pip install "nemo-fabric-adapters-codex[harness]"` | No | Yes | Yes | No | | `pip install nemo-fabric-adapters-codex` | No | Yes | No | No | -For an environment-managed SDK, use `openai-codex==0.144.4`. For split runtime -and adapter environments, configure `ADAPTER_PYTHON` or -`harness.settings.python` and use matching NeMo Fabric release versions. Refer -to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-an-adapter-and-harness-without-the-runtime). +The `full` extra is equivalent to `harness`. NeMo Relay is optional for ordinary +runs. NeMo Relay telemetry and streaming require the `nemo-relay` CLI tool to be installed, refer to the [NeMo Relay installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#nemo-relay-cli). -The `full` extra is equivalent to `harness`. Relay is optional for ordinary -runs. Relay telemetry and `Runtime.invoke_stream()` require the external CLI -described under [Relay Integration](#relay-integration). - -## Authentication - -NeMo Fabric reuses the authentication state that Codex stores under `CODEX_HOME` -(default: `~/.codex`). NeMo Fabric does not perform an interactive login, copy -credentials, or mutate the user's Codex configuration. - -Codex supports two OpenAI authentication modes: - -- **ChatGPT login:** Sign in through Codex with a ChatGPT plan. NeMo Fabric can then - run without `OPENAI_API_KEY` while that cached login remains valid. -- **API key login:** Provision the same Codex credential store with an OpenAI - API key. This mode uses OpenAI Platform billing rather than ChatGPT plan - credits. - -For a nondefault credential store, set `CODEX_HOME` before both login and the -NeMo Fabric invocation. Treat `CODEX_HOME/auth.json` as a secret when Codex uses -file-based credential storage. Refer to the -[Codex authentication documentation](https://developers.openai.com/codex/auth/) -for login, headless setup, and credential-storage options. - -The adapter forwards `OPENAI_API_KEY` and a selected model's `api_key_env` to -the SDK runtime. The current real-agent acceptance path validates an existing -Codex login; it does not yet claim a raw environment variable as a complete -login flow. - -The native `openai` provider retains Codex authentication and endpoint -discovery. For another provider name, configure both -`models..api_key_env` and `models..base_url`. The endpoint must -implement the OpenAI Responses protocol. The adapter defines a runtime-scoped -Codex model provider with that name and isolates its Codex state under the -NeMo Fabric artifact root, so execution does not depend on or modify a user's -Codex login. Provider names identify configuration; the adapter does not -maintain a provider allowlist. - -The adapter uses the Codex SDK, which installs and selects its matching -app-server runtime. NeMo Fabric does not declare the runtime package directly or -treat it as a user-installed command or adapter descriptor requirement. - -A `codex` command on `PATH` is not selected implicitly. - -## Execution Model - -Each NeMo Fabric runtime currently starts one local adapter host and retains one -`AsyncCodex` client and one Codex thread. The Codex starts and controls its -pinned local `codex app-server` subprocess over JSON-RPC. Ordered -`Runtime.invoke(...)` calls reuse that client and thread directly; the adapter -closes the SDK client and app-server transport during `Runtime.stop()`. Codex -owns the transcript; NeMo Fabric owns runtime-to-thread correlation, timeout, -cancellation, and cleanup. - -The result includes the SDK's typed terminal response, turn status, token -usage, timing, and completed thread items. It does not expose CLI commands, -return codes, stdout, or stderr. - -## Configuration - -Use normalized `FabricConfig` fields for portable configuration: - -- `models` selects the Codex model. The native `openai` provider retains Codex - authentication and endpoint discovery. Any other provider name must configure - a Responses-compatible `base_url` and `api_key_env`. -- `instructions.system` maps to Codex base instructions. -- `runtime.timeout_seconds` sets the NeMo Fabric invocation deadline. -- `environment.workspace` sets the working directory, and `environment.env` - supplies explicit harness-visible variables. -- `mcp` maps stdio, HTTP, and streamable HTTP servers into the Codex thread's - `mcp_servers` configuration. For stdio, NeMo Fabric parses `url` as a command plus - arguments. -- `skills.paths` names skill directories that contain `SKILL.md`. The adapter - registers each directory as a process-scoped Codex skill root so Codex can - select matching skills through its normal discovery behavior. -- `telemetry` enables native OpenTelemetry or NeMo Relay observability. - -The Codex adapter does not declare `tools.blocked` support. The current Codex -runtime has per-MCP-server tool filters, but it does not provide one complete -deny boundary for built-in, local, MCP, and hosted tools. NeMo Fabric therefore -routes normalized blocked-tool policy as unsupported instead of applying a -partial policy. - -Codex-specific controls belong in `harness.settings`: - -- `sandbox`: `read-only`, `workspace-write`, or `danger-full-access` -- `approval_mode`: `auto_review` or `deny_all` -- `developer_instructions` -- `personality`, `reasoning_effort`, and `service_tier` -- `output_schema` for SDK-native structured output -- `config_overrides` as dotted Codex configuration keys applied when the SDK - runtime starts, such as Codex-only MCP timeout or required-server options - -Set model selection and endpoints through `models`, system instructions through -`instructions.system`, the invocation deadline through -`runtime.timeout_seconds`, and the working directory and explicit environment -through `environment`. - -For `Fabric.start_runtime(...)`, the model provider, MCP configuration, skill -roots, and `config_overrides` are fixed when the runtime starts and cannot vary -between `Runtime.invoke(...)` calls. Start a new runtime to change them. -`Fabric.run(...)` starts the same runtime, invokes it once, and stops it, so the -same settings are scoped to that single invocation. - -The adapter filters the inherited environment. It retains portable OS and -Codex state variables, the selected model's `api_key_env`, and explicit -`environment.env` values while clearing unrelated parent-process secrets. - -## Relay Integration - -Relay requires a separately installed NeMo Relay 0.6.x CLI on `PATH`; the Python -`nemo-relay` package does not provide the executable. Follow the -[NeMo Relay installation instructions](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-nemo-relay). - -Enable Relay with `FabricConfig.enable_relay(...)`. The adapter starts the -installed `nemo-relay` CLI as a supervised sidecar; do not start the gateway -separately. -NeMo Fabric routes the selected Responses-compatible provider through the -gateway and passes its explicit `base_url` to Relay as the upstream endpoint. +Refer to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install) for more details. \ No newline at end of file diff --git a/adapters/common/pypi.md b/adapters/common/pypi.md index f0ac1250..a0af083c 100644 --- a/adapters/common/pypi.md +++ b/adapters/common/pypi.md @@ -9,9 +9,11 @@ SPDX-License-Identifier: Apache-2.0 [![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) [![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) -`nemo-fabric-adapters-common` provides shared Python helpers for NeMo Fabric -adapter implementations. Adapter packages normally install -this package as a dependency. +`nemo-fabric-adapters-common` provides shared helper methods for NeMo Fabric +adapter implementations. Adapter packages typically declare this package as a +dependency. + +## Install Install the package directly when developing an adapter: @@ -21,40 +23,4 @@ pip install nemo-fabric-adapters-common Refer to the [NeMo Fabric documentation](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric) for adapter and configuration guidance. Source code is available in the -[NVIDIA NeMo Fabric repository](https://github.com/NVIDIA/nemo-fabric/). - -## Persistent Local Hosts - -Every local Process or Python adapter implements the ordered persistent-host -wire protocol. Python adapters can use -`nemo_fabric_adapters.common.lifecycle`. Supply a factory that creates one -adapter-owned runtime with asynchronous `start`, `invoke`, and `stop` methods: - -```python -from nemo_fabric_adapters.common import lifecycle - - -class AdapterRuntime: - async def start(self, payload): - self.client = await connect_client(payload) - - async def invoke(self, payload): - return await self.client.run(payload["request"]["input"]) - - async def stop(self): - await self.client.close() - - -lifecycle.serve(AdapterRuntime) -``` - -NeMo Fabric calls the factory once per local host to create one runtime instance and -serializes invocations through that instance. The host keeps one event loop -alive for the complete lifecycle so SDK clients, compiled graphs, -checkpointers, and harness databases can remain live safely. NeMo Fabric sends the -resolved configuration and capability plan during `start`. Each subsequent -`invoke` wire payload contains only `runtime_context` and `request`, and the -helper passes that payload to `AdapterRuntime.invoke` unchanged. An adapter that -needs configuration during invocation retains it as runtime-owned state during -`start`. Adapter stdout is reserved for the protocol; diagnostics are redirected -to stderr. A host crash or protocol timeout terminates that runtime. +[NVIDIA NeMo Fabric repository](https://github.com/NVIDIA/NeMo-Fabric). diff --git a/adapters/deepagents/pypi.md b/adapters/deepagents/pypi.md index 819a21fc..1bcaef1b 100644 --- a/adapters/deepagents/pypi.md +++ b/adapters/deepagents/pypi.md @@ -9,13 +9,11 @@ SPDX-License-Identifier: Apache-2.0 [![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) [![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) -Runs a [LangChain Deep Agents](https://github.com/langchain-ai/deepagents) agent -inside NeMo Fabric's persistent Python adapter host. One started runtime retains the -compiled graph, checkpointer, and LangGraph thread across ordered invocations. +Provides a NeMo Fabric adapter for use with [LangChain Deep Agents](https://www.langchain.com/deep-agents). ## Install -The following table shows which components each installation provides: +Installation can be performed using the `nemo-fabric` meta package with the `deepagents` extra, or by installing the adapter and harness packages separately. The following table shows which components each installation provides: | Installation | Runtime | Adapter | Harness | NeMo Relay Python Package | | --- | --- | --- | --- | --- | @@ -26,191 +24,8 @@ The following table shows which components each installation provides: | `pip install "nemo-fabric-adapters-deepagents[relay]"` | No | Yes | No | Yes | | `pip install nemo-fabric-adapters-deepagents` | No | Yes | No | No | -For an environment-managed stack, use `deepagents>=0.6.12,<0.7.0`, -`langchain>=1.3,<2.0`, and `langgraph>=1.2,<2.0`. For split runtime and adapter -environments, configure `ADAPTER_PYTHON` or `harness.settings.python` and use -matching NeMo Fabric release versions. Refer to the -[installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-an-adapter-and-harness-without-the-runtime). +NeMo Relay is optional for ordinary runs. NeMo Relay telemetry and streaming +require one of the installations in the table that includes the NeMo Relay +Python package. -## Model and Authentication - -The adapter builds a LangChain chat model from the selected NeMo Fabric model -role: `models.default`, or the sole configured role when `default` is absent. -The `openai`, `nvidia`, and `openai-compatible` providers use `ChatOpenAI`; -`nvidia` and `openai-compatible` require an explicit compatible `base_url`. -Any other provider is constructed through -`langchain.chat_models.init_chat_model`, so LangChain-supported backends do not -require adapter-specific branches. - -`models..api_key_env` names the environment variable holding the API key, -and defaults to `OPENAI_API_KEY` only for the native `openai` provider. Every -other provider must set `api_key_env` explicitly (a missing one is a normalized -configuration failure), so a key is never sent to the wrong endpoint. - -Because `models..api_key_env` is provider-specific, the adapter declares no -static env requirement; a runtime **preflight** verifies that the `deepagents` -package is importable and the configured credential is set. A failed preflight -fails runtime start with a stable lifecycle error. - -NeMo Fabric maps the following into the harness: - -- The selected `models` role supplies `model`, `provider`, `api_key_env`, - `base_url`, and `temperature`. -- `instructions.system` becomes the Deep Agents `system_prompt`. -- `runtime.timeout_seconds` sets the NeMo Fabric invocation deadline. -- `environment.workspace` roots the Deep Agents filesystem backend - (`FilesystemBackend(root_dir=..., virtual_mode=True)`). `virtual_mode` - confines the agent to the workspace: absolute paths and `..` cannot escape - `root_dir`. -- Routed `skills` (`native.skill_paths`) become the Deep Agents `skills` sources. -- Configured MCP servers are loaded as Deep Agents tools via - `langchain-mcp-adapters`. A misconfigured server (non-mapping, empty target, - unsupported transport) is a normalized configuration failure, not a silent drop. -- `tools.enabled` and `tools.blocked` are enforced by middleware across the full - tool surface: Deep Agents built-ins (including `task`), MCP tools, and - **delegated subagents** alike. Use Deep Agents-native tool names. -- `harness.settings.deepagents` forwards a small set of **documented, - JSON-serializable** `create_deep_agent` options (currently `subagents` and - `interrupt_on`). It is not a general Python-object escape hatch: the SDK config - round-trips through JSON and Rust planning, so `AgentMiddleware`, `BaseTool` - instances, and Python callables cannot cross the boundary. NeMo Fabric-owned - arguments (`model`, `tools`, `backend`, `skills`, `system_prompt`, `middleware`, - `checkpointer`) cannot be overridden through this passthrough, and an unknown or - unsupported key is an adapter configuration failure rather than a silently - dropped setting. - -### Subagents - -Deep Agents can delegate to subagents through its built-in `task` tool. Subagents -**inherit** the parent run's model, tools, skills, workspace, telemetry, and -permissions. When a normalized tools policy is configured, NeMo Fabric supplies -an explicitly gated `general-purpose` subagent and gates every declarative local -subagent, so delegation cannot broaden capabilities beyond the parent. Remote -and precompiled subagents are rejected in that case because their execution -cannot be governed by the local middleware. Independently configured subagent tools, skills, models, -MCP servers, middleware, or permissions are **not** exposed through the NeMo Fabric SDK -yet; a `subagents` definition here only carries JSON-shaped fields. - -The normalized result includes the final response, buffered messages and -per-step events, LangGraph thread id, token usage (and cost when the provider -reports it), and errors. Usage aggregates the current turn across the main agent -and any delegated subagents (streamed with `subgraphs=True`). Configuration and -preflight failures (a missing credential, an absent `deepagents` package, an -invalid MCP server, or a passthrough option) fail runtime start before an -invocation is accepted. - -## Runtime Lifecycle - -NeMo Fabric starts one local adapter host for every runtime. During runtime start, -the host compiles one Deep Agents graph, opens its async LangGraph checkpointer, -and creates one thread ID. Every invocation reuses those native objects; later -turns report `resumed` as `true`. The checkpointer lives under -the NeMo Fabric artifact root, scoped by runtime ID, and is closed during -runtime stop. The live host owns the thread identity, and LangGraph owns the -transcript. - -`Fabric.run(...)` is a convenience over that same lifecycle: it starts the -runtime, invokes it once, and stops it. It does not use a separate adapter -entrypoint or execution path. - -The `deepagents_config()` builder in `examples/code_review_agent` is the SDK -example. Run it from the CLI with -`python -m examples.code_review_agent --variant deepagents --input "..."`, or -drive the SDK directly: - -```python -from examples.code_review_agent import BASE_DIR, deepagents_config -from nemo_fabric import Fabric - -config = deepagents_config() -client = Fabric() - -# Single invocation through the standard runtime lifecycle. -result = await client.run( - config, base_dir=BASE_DIR, input="Review the workspace changes." -) -print(result["output"]["response"]) - -# Multi-turn: one started runtime keeps the LangGraph thread across turns. -async with await client.start_runtime(config, base_dir=BASE_DIR) as runtime: - await runtime.invoke(input="Remember the value 42.") - reply = await runtime.invoke(input="What value did I ask you to remember?") - # reply["output"]["resumed"] is True and the response recalls "42". - print(reply["output"]["resumed"], reply["output"]["response"]) -``` - -## Telemetry - -NeMo Relay is Deep Agents' single, SDK-native observability path — the adapter -does not expose gateway, CLI, or plugin launch modes for this harness. Relay is -**optional**: `nemo_relay` is imported lazily and only when telemetry is enabled, -so the core install stays Relay-neutral at import time. Relay telemetry and -`Runtime.invoke_stream()` require one of the installations in the table that -includes the NeMo Relay Python package. - -- **Relay** (`telemetry.providers.relay`): the SDK-native integration attaches - three complementary pieces around `create_deep_agent`, applied uniformly to - single-invocation, multi-turn, and subagent-enabled runs: - - `nemo_relay.integrations.deepagents.add_nemo_relay_integration(...)` injects - Deep Agents-aware **middleware** that routes model and tool calls through - Relay and emits skill/subagent configuration marks. - - The top-level invocation runs inside a - `nemo_relay.scope.scope("deepagents-request", nemo_relay.ScopeType.Agent)` - scope, so the whole NeMo Fabric turn is captured under one Agent scope. - - `NemoRelayDeepAgentsCallbackHandler()` is added to the LangGraph run config - (without dropping consumer-provided callbacks) to capture LangGraph scopes - and human-in-the-loop interrupt/resume marks. - - Runs emit ATOF/ATIF artifacts to the configured output directory, referenced in - the normalized result's `relay_artifacts` (and the `RunResult` `ArtifactManifest`). - OTel/OpenInference export is available through the relay plugin config; the - example provides `with_relay_otel(...)` and - `with_relay_openinference(...)` variants. -- **Native** (`telemetry.providers.native.config`): the provider config - OpenTelemetry/OpenInference exporter is applied and spans export directly to - the configured collector, without writing ATOF/ATIF relay artifacts. - -**Subagent boundary.** In-process, dictionary-style subagents are instrumented -with the same Relay middleware, so their model/tool calls appear under the same -trajectory. Remote and precompiled subagents (those defined with `graph_id` or -`url`) are **out of scope**: their internals execute in a separate runtime and -must be instrumented there with their own Relay integration. - -### Typed Relay configuration - -Enable Relay on a `FabricConfig` with the typed helpers — no gateway process or -CLI flags are involved: - -```python -from nemo_fabric import ( - RelayAtifConfig, - RelayAtofConfig, - RelayAtofFileSinkConfig, - RelayObservabilityConfig, -) -from examples.code_review_agent import deepagents_config - -# Start from a complete Deep Agents configuration, then enable typed Relay telemetry. -config = deepagents_config() -config.enable_relay( - output_dir="./artifacts/relay", - observability=RelayObservabilityConfig( - atof=RelayAtofConfig( - enabled=True, - sinks=[ - RelayAtofFileSinkConfig( - output_directory="./artifacts/relay", - filename="events.atof.jsonl", - mode="overwrite", - ) - ], - ), - atif=RelayAtifConfig( - enabled=True, - output_directory="./artifacts/relay", - filename_template="trajectory-{session_id}.atif.json", - agent_name="deepagents-agent", - ), - ), -) -``` +Refer to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install) for more details. diff --git a/adapters/hermes/pypi.md b/adapters/hermes/pypi.md index 00c2914e..b97b9383 100644 --- a/adapters/hermes/pypi.md +++ b/adapters/hermes/pypi.md @@ -9,12 +9,12 @@ SPDX-License-Identifier: Apache-2.0 [![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) [![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) -This adapter runs Hermes Agent through its Python SDK. +Provides a NeMo Fabric adapter for use with [Hermes Agent](https://hermes-agent.nousresearch.com/). ## Install -Hermes Agent and this adapter require Python 3.11 through 3.13. The following -table shows which components each installation provides: +Hermes Agent and this adapter require Python versions 3.11 through 3.13. +Installation can be performed using the `nemo-fabric` meta package with the `hermes-agent` extra, or by installing the adapter and harness packages separately. The following table shows which components each installation provides: | Installation | Runtime | Adapter | Harness | NeMo Relay Python Package | | --- | --- | --- | --- | --- | @@ -25,47 +25,9 @@ table shows which components each installation provides: | `pip install "nemo-fabric-adapters-hermes[relay]"` | No | Yes | No | Yes | | `pip install nemo-fabric-adapters-hermes` | No | Yes | No | No | -For an environment-managed harness, use `hermes-agent>=0.17.0`. For split -runtime and adapter environments, configure `ADAPTER_PYTHON` or -`harness.settings.python` and use matching NeMo Fabric release versions. Refer -to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-an-adapter-and-harness-without-the-runtime). +NeMo Relay is optional for ordinary runs. NeMo Relay telemetry and streaming +require one of the installations in the table that includes the NeMo Relay +Python package. -Relay is optional for ordinary runs. Relay telemetry and -`Runtime.invoke_stream()` require one of the installations in the table that -includes the NeMo Relay Python package. +Refer to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install) for more details. -## What It Maps - -The adapter receives a normalized payload from NeMo Fabric and materializes a native Hermes Agent configuration for: - -- selected model provider, model name, base URL, and temperature through - `models`; -- `instructions.system` and `runtime.max_turns`; -- workspace and explicit environment variables through `environment`; -- invocation timeout through `runtime.timeout_seconds`; -- NeMo Fabric skills as external skill directories for Hermes Agent; -- NeMo Fabric MCP servers as Hermes Agent MCP server config; -- `tools.enabled` and `tools.blocked` as Hermes-native toolset selection and - blocking policy; -- optional NeMo Relay telemetry plugin configuration. - -Tool selectors are Hermes toolset names because that is the native policy -surface Hermes exposes. Keep Hermes-specific controls such as -terminal timeout, reasoning configuration, and plugin configuration in -`harness.settings`. The adapter derives Hermes state from the NeMo Fabric -artifact root and creates a child under `runtimes/`, so invocations -in one NeMo Fabric runtime share state without sharing config or the session -database with another runtime. - -## Execution Model - -Each NeMo Fabric runtime starts one local adapter host, constructs one Hermes Agent -`AIAgent`, and opens one `SessionDB`. Ordered `Runtime.invoke(...)` calls reuse -those native objects and pass the prior turn's returned transcript back to -`run_conversation(...)`. Runtime stop calls the agent's idempotent `close()` -method, closes the session database, and releases the Relay plugin context when -enabled. - -Hermes Agent Relay telemetry is finalized after each NeMo Fabric invocation so its ATOF -and ATIF artifacts are complete when that invocation returns. This telemetry -boundary does not recreate the `AIAgent` or `SessionDB`. diff --git a/python/pypi.md b/python/pypi.md index 41fbc053..ceabae85 100644 --- a/python/pypi.md +++ b/python/pypi.md @@ -12,7 +12,7 @@ SPDX-License-Identifier: Apache-2.0 `nemo-fabric-runtime` provides the Python SDK and native Rust bindings for NVIDIA NeMo Fabric, a runtime execution layer for agents. -Typically this is installed using the [`nemo-fabric`](https://pypi.org/project/nemo-fabric/) meta-package. +Typically this is installed using the [`nemo-fabric`](https://pypi.org/project/nemo-fabric/) meta package. ```bash pip install nemo-fabric From 1d03a5b6f8a5db50d005a77154f9c903abc1ab85 Mon Sep 17 00:00:00 2001 From: David Gardner Date: Wed, 29 Jul 2026 10:22:46 -0700 Subject: [PATCH 12/15] Merge testing information back into the README Signed-off-by: David Gardner --- adapters/codex/README.md | 25 +++++++++++++++++++++++++ adapters/codex/testing.md | 28 ---------------------------- 2 files changed, 25 insertions(+), 28 deletions(-) delete mode 100644 adapters/codex/testing.md diff --git a/adapters/codex/README.md b/adapters/codex/README.md index 7d81a83d..de101ce1 100644 --- a/adapters/codex/README.md +++ b/adapters/codex/README.md @@ -144,3 +144,28 @@ installed `nemo-relay` CLI as a supervised sidecar; do not start the gateway separately. NeMo Fabric routes the selected Responses-compatible provider through the gateway and passes its explicit `base_url` to Relay as the upstream endpoint. + + +## Testing + +Run the unit and opt-in real SDK tests separately: + +```bash +uv run pytest tests/adapters/test_codex_adapter.py -q +RUN_FABRIC_CODEX_INTEGRATION=1 uv run pytest tests/e2e/test_codex.py -q +RUN_FABRIC_CODEX_RELAY_INTEGRATION=1 \ + FABRIC_TEST_NEMO_RELAY_COMMAND=/path/to/nemo-relay \ + uv run pytest tests/e2e/test_codex.py -q +``` + +Set `FABRIC_TEST_CODEX_BIN=/path/to/codex` on either opt-in command to validate +an explicit app-server override instead of the SDK-pinned runtime. + +The SDK test uses the current Codex authentication state and exercises both the +single-invocation convenience API and multiple turns against one started +runtime. The Relay test additionally requires an external gateway binary and +verifies model responses, stable thread identity across turns, Agent Trajectory +Observability Format (ATOF), and Agent Trajectory Interchange Format (ATIF); +gateway startup alone is not a passing result. The semantic regression requires +the LLM request content to be decoded. It also requires ATIF to contain the +model, token usage, and expected agent response. diff --git a/adapters/codex/testing.md b/adapters/codex/testing.md deleted file mode 100644 index d5ccd987..00000000 --- a/adapters/codex/testing.md +++ /dev/null @@ -1,28 +0,0 @@ - - -# Testing the Codex Adapter - -Run the unit and opt-in real SDK tests separately: - -```bash -uv run pytest tests/adapters/test_codex_adapter.py -q -RUN_FABRIC_CODEX_INTEGRATION=1 uv run pytest tests/e2e/test_codex.py -q -RUN_FABRIC_CODEX_RELAY_INTEGRATION=1 \ - FABRIC_TEST_NEMO_RELAY_COMMAND=/path/to/nemo-relay \ - uv run pytest tests/e2e/test_codex.py -q -``` - -Set `FABRIC_TEST_CODEX_BIN=/path/to/codex` on either opt-in command to validate -an explicit app-server override instead of the SDK-pinned runtime. - -The SDK test uses the current Codex authentication state and exercises both the -single-invocation convenience API and multiple turns against one started -runtime. The Relay test additionally requires an external gateway binary and -verifies model responses, stable thread identity across turns, Agent Trajectory -Observability Format (ATOF), and Agent Trajectory Interchange Format (ATIF); -gateway startup alone is not a passing result. The semantic regression requires -the LLM request content to be decoded. It also requires ATIF to contain the -model, token usage, and expected agent response. From ff1613417e48a67e11aadc159c906002175e5a0b Mon Sep 17 00:00:00 2001 From: David Gardner Date: Wed, 29 Jul 2026 10:51:42 -0700 Subject: [PATCH 13/15] Add NeMo Fabric logo image to all pypi.md files Signed-off-by: David Gardner --- adapters/claude/pypi.md | 3 ++- adapters/codex/pypi.md | 4 +++- adapters/common/pypi.md | 2 ++ adapters/deepagents/pypi.md | 2 ++ adapters/hermes/pypi.md | 3 ++- pypi.md | 2 ++ python/pypi.md | 2 ++ 7 files changed, 15 insertions(+), 3 deletions(-) diff --git a/adapters/claude/pypi.md b/adapters/claude/pypi.md index 02534faa..c9f75a83 100644 --- a/adapters/claude/pypi.md +++ b/adapters/claude/pypi.md @@ -9,6 +9,8 @@ SPDX-License-Identifier: Apache-2.0 [![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) [![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) +![Diagram showing NeMo Fabric connecting applications, evaluations, and reinforcement learning rollouts to Hermes, Codex, Claude, and Deep Agents, with results, artifacts, and telemetry as outputs.](https://raw.githubusercontent.com/NVIDIA/NeMo-Fabric/refs/heads/main/assets/fabric-hero-option2.png) + Provides a NeMo Fabric adapter for use with [Claude Code](https://claude.com/). ## Install @@ -25,4 +27,3 @@ The `full` extra is equivalent to `harness`. Relay is optional for ordinary runs. NeMo Relay telemetry and streaming require the `nemo-relay` CLI tool to be installed, refer to the [NeMo Relay installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#nemo-relay-cli). Refer to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install) for more details. - diff --git a/adapters/codex/pypi.md b/adapters/codex/pypi.md index d928ae4b..72bdfa36 100644 --- a/adapters/codex/pypi.md +++ b/adapters/codex/pypi.md @@ -9,6 +9,8 @@ SPDX-License-Identifier: Apache-2.0 [![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) [![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) +![Diagram showing NeMo Fabric connecting applications, evaluations, and reinforcement learning rollouts to Hermes, Codex, Claude, and Deep Agents, with results, artifacts, and telemetry as outputs.](https://raw.githubusercontent.com/NVIDIA/NeMo-Fabric/refs/heads/main/assets/fabric-hero-option2.png) + Provides a NeMo Fabric adapter for use with [Codex](https://openai.com/codex/). ## Install @@ -24,4 +26,4 @@ Installation can be performed using the `nemo-fabric` meta package with the `cod The `full` extra is equivalent to `harness`. NeMo Relay is optional for ordinary runs. NeMo Relay telemetry and streaming require the `nemo-relay` CLI tool to be installed, refer to the [NeMo Relay installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#nemo-relay-cli). -Refer to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install) for more details. \ No newline at end of file +Refer to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install) for more details. diff --git a/adapters/common/pypi.md b/adapters/common/pypi.md index a0af083c..354f67c4 100644 --- a/adapters/common/pypi.md +++ b/adapters/common/pypi.md @@ -9,6 +9,8 @@ SPDX-License-Identifier: Apache-2.0 [![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) [![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) +![Diagram showing NeMo Fabric connecting applications, evaluations, and reinforcement learning rollouts to Hermes, Codex, Claude, and Deep Agents, with results, artifacts, and telemetry as outputs.](https://raw.githubusercontent.com/NVIDIA/NeMo-Fabric/refs/heads/main/assets/fabric-hero-option2.png) + `nemo-fabric-adapters-common` provides shared helper methods for NeMo Fabric adapter implementations. Adapter packages typically declare this package as a dependency. diff --git a/adapters/deepagents/pypi.md b/adapters/deepagents/pypi.md index 1bcaef1b..f5f9bc3f 100644 --- a/adapters/deepagents/pypi.md +++ b/adapters/deepagents/pypi.md @@ -9,6 +9,8 @@ SPDX-License-Identifier: Apache-2.0 [![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) [![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) +![Diagram showing NeMo Fabric connecting applications, evaluations, and reinforcement learning rollouts to Hermes, Codex, Claude, and Deep Agents, with results, artifacts, and telemetry as outputs.](https://raw.githubusercontent.com/NVIDIA/NeMo-Fabric/refs/heads/main/assets/fabric-hero-option2.png) + Provides a NeMo Fabric adapter for use with [LangChain Deep Agents](https://www.langchain.com/deep-agents). ## Install diff --git a/adapters/hermes/pypi.md b/adapters/hermes/pypi.md index b97b9383..798a1cbc 100644 --- a/adapters/hermes/pypi.md +++ b/adapters/hermes/pypi.md @@ -9,6 +9,8 @@ SPDX-License-Identifier: Apache-2.0 [![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) [![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) +![Diagram showing NeMo Fabric connecting applications, evaluations, and reinforcement learning rollouts to Hermes, Codex, Claude, and Deep Agents, with results, artifacts, and telemetry as outputs.](https://raw.githubusercontent.com/NVIDIA/NeMo-Fabric/refs/heads/main/assets/fabric-hero-option2.png) + Provides a NeMo Fabric adapter for use with [Hermes Agent](https://hermes-agent.nousresearch.com/). ## Install @@ -30,4 +32,3 @@ require one of the installations in the table that includes the NeMo Relay Python package. Refer to the [installation guide](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install) for more details. - diff --git a/pypi.md b/pypi.md index 63dbec19..c53e54cf 100644 --- a/pypi.md +++ b/pypi.md @@ -9,6 +9,8 @@ SPDX-License-Identifier: Apache-2.0 [![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) [![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) +![Diagram showing NeMo Fabric connecting applications, evaluations, and reinforcement learning rollouts to Hermes, Codex, Claude, and Deep Agents, with results, artifacts, and telemetry as outputs.](https://raw.githubusercontent.com/NVIDIA/NeMo-Fabric/refs/heads/main/assets/fabric-hero-option2.png) + NeMo Fabric gives applications one configurable, observable way to run applications across multiple agent harnesses. It standardizes configuration, lifecycle management, and results without requiring a separate integration for every harness. diff --git a/python/pypi.md b/python/pypi.md index ceabae85..d2320818 100644 --- a/python/pypi.md +++ b/python/pypi.md @@ -9,6 +9,8 @@ SPDX-License-Identifier: Apache-2.0 [![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Fabric/) [![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Fabric?color=green)](https://github.com/NVIDIA/NeMo-Fabric/releases) +![Diagram showing NeMo Fabric connecting applications, evaluations, and reinforcement learning rollouts to Hermes, Codex, Claude, and Deep Agents, with results, artifacts, and telemetry as outputs.](https://raw.githubusercontent.com/NVIDIA/NeMo-Fabric/refs/heads/main/assets/fabric-hero-option2.png) + `nemo-fabric-runtime` provides the Python SDK and native Rust bindings for NVIDIA NeMo Fabric, a runtime execution layer for agents. From a6adfba4349aa32d4f28df1b29dcd9849401aeeb Mon Sep 17 00:00:00 2001 From: David Gardner Date: Wed, 29 Jul 2026 11:36:34 -0700 Subject: [PATCH 14/15] Trim down the main pypi file Signed-off-by: David Gardner --- pypi.md | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/pypi.md b/pypi.md index c53e54cf..b13e3e5e 100644 --- a/pypi.md +++ b/pypi.md @@ -30,15 +30,22 @@ It provides: ## Install -NeMo Fabric supports Python 3.11 through 3.14. Use Python 3.11 through 3.13 for -Hermes Agent; the Harbor integration requires Python 3.12 or later. - Install the core runtime and Python SDK: ```bash pip install nemo-fabric ``` +### Supported Harnesses + +| Agent Harness | Runtime, Adapter, and Harness | Adapter and Harness | Adapter Only | +| --- | --- | --- | --- | +| [Claude Code](https://pypi.org/project/nemo-fabric-adapters-claude/) | `nemo-fabric[claude]` | `nemo-fabric-adapters-claude[harness]` | `nemo-fabric-adapters-claude` | +| [Codex](https://pypi.org/project/nemo-fabric-adapters-codex/) | `nemo-fabric[codex]` | `nemo-fabric-adapters-codex[harness]` | `nemo-fabric-adapters-codex` | +| [Hermes Agent](https://pypi.org/project/nemo-fabric-adapters-hermes/) | `nemo-fabric[hermes-agent]` | `nemo-fabric-adapters-hermes[harness]` | `nemo-fabric-adapters-hermes` | +| [LangChain Deep Agents](https://pypi.org/project/nemo-fabric-adapters-deepagents/) | `nemo-fabric[deepagents]` | `nemo-fabric-adapters-deepagents[harness]` | `nemo-fabric-adapters-deepagents` | + + To install the NeMo Fabric runtime, adapter, and supported harness in one environment, choose one of the following `nemo-fabric` harness extras: @@ -79,11 +86,6 @@ does not install the NeMo Fabric runtime. Select `harness` or `full` to install the harness. If the runtime shares an environment with an existing compatible harness, install `nemo-fabric` and the bare adapter package together. -NeMo Fabric supports running an agent harness in a different virtual -environment from the NeMo Fabric runtime. This separation can isolate harnesses -that have conflicting dependencies. Use matching NeMo Fabric release versions -for the runtime and adapter package unless a different pairing has been -explicitly validated. ### Integrations @@ -110,23 +112,3 @@ Claude and Codex require the Relay Python package. They do not provide a `relay` extra. Refer to the [NeMo Relay CLI](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-nemo-relay) install guide for instructions on installing the CLI tool. - -## Core Concepts - -- **Typed configuration:** Construct a complete `FabricConfig` in Python and - use ordinary functions to create experiment variants. -- **Adapters:** Select harness-specific integrations with - `harness.adapter_id`. -- **Artifacts:** Receive normalized output, logs, patches, and telemetry - references through an `ArtifactManifest`. - -The experimental `nemo-fabric` CLI is distributed separately from the Python -package. It selects complete typed configs from built-in presets and maintained -examples. Applications that need a stable integration surface should use the -Python SDK. - -## Learn More - -Refer to the [NVIDIA NeMo Fabric documentation](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric) -for installation, configuration, and usage guidance. Source code is available -in the [NVIDIA NeMo Fabric repository](https://github.com/NVIDIA/nemo-fabric/). From eb43f9683c385829b88f9b72b8bda0424c240824 Mon Sep 17 00:00:00 2001 From: David Gardner Date: Wed, 29 Jul 2026 11:36:53 -0700 Subject: [PATCH 15/15] Restore the learn more section Signed-off-by: David Gardner --- pypi.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pypi.md b/pypi.md index b13e3e5e..2b89ac1a 100644 --- a/pypi.md +++ b/pypi.md @@ -112,3 +112,9 @@ Claude and Codex require the Relay Python package. They do not provide a `relay` extra. Refer to the [NeMo Relay CLI](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric/getting-started/install#install-nemo-relay) install guide for instructions on installing the CLI tool. + +## Learn More + +Refer to the [NVIDIA NeMo Fabric documentation](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric) +for installation, configuration, and usage guidance. Source code is available +in the [NVIDIA NeMo Fabric repository](https://github.com/NVIDIA/nemo-fabric/).