diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.github/actions/setup-nix/action.yaml b/.github/actions/setup-nix/action.yaml new file mode 100644 index 0000000..9c735d6 --- /dev/null +++ b/.github/actions/setup-nix/action.yaml @@ -0,0 +1,19 @@ +name: "Setup Nix" +description: "Install Nix and configure Cachix" +runs: + using: "composite" + steps: + - name: Install Nix + uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31.8.4 + with: + github_access_token: ${{ github.token }} + + - name: Setup Cachix (numtide) + uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 + with: + name: numtide + authToken: "" + + - name: Load Nix development environment + shell: bash + run: nix develop --command true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..963ec73 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,54 @@ +name: CI + +on: + push: + pull_request: + branches: + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + ci: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.9", "3.10", "3.13"] + include: + - python-version: "3.9" + sync-extras: "--all-extras --no-extra mcp" + - python-version: "3.10" + sync-extras: "--all-extras" + - python-version: "3.13" + sync-extras: "--all-extras" + env: + STACKONE_API_KEY: ${{ secrets.STACKONE_API_KEY }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + steps: + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - name: Setup Nix + uses: ./.github/actions/setup-nix + + - name: Install dependencies + run: nix develop --command uv sync ${{ matrix.sync-extras }} + + - name: Run Lint + run: nix develop --command uv run ruff check . + + - name: Run Mypy + run: | + if [[ "${{ matrix.python-version }}" == "3.9" ]]; then + nix develop --command uv run mypy stackone_ai --exclude stackone_ai/server.py + else + nix develop --command uv run mypy stackone_ai + fi + + - name: Run Tests + run: nix develop --command uv run pytest diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index cd1233b..8a43ef3 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -12,21 +12,19 @@ jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - name: Install uv - uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1 - with: - python-version: "3.11" - enable-cache: true + - name: Setup Nix + uses: ./.github/actions/setup-nix - name: Install all dependencies - run: uv sync --all-extras + run: nix develop --command uv sync --all-extras - name: Build documentation run: | - uv run scripts/build_docs.py - uv run mkdocs build + nix develop --command uv run scripts/build_docs.py + nix develop --command uv run mkdocs build - name: Deploy to GitHub Pages if: github.ref == 'refs/heads/main' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 2324a19..0000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Lint & Type Check - -on: - pull_request: - branches: - - main - -jobs: - lint: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.9", "3.10"] - include: - - python-version: "3.9" - sync-extras: "--all-extras --no-extra mcp" - - python-version: "3.10" - sync-extras: "--all-extras" - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - - name: Install uv - uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1 - with: - python-version: ${{ matrix.python-version }} - enable-cache: true - - - name: Install dependencies - run: uv sync ${{ matrix.sync-extras }} - - - name: Run Ruff - uses: astral-sh/ruff-action@57714a7c8a2e59f32539362ba31877a1957dded1 # v3.5.1 - with: - args: check . - - - name: Run Mypy - run: | - if [[ "${{ matrix.python-version }}" == "3.9" ]]; then - uv run mypy stackone_ai --exclude stackone_ai/server.py - else - uv run mypy stackone_ai - fi diff --git a/.github/workflows/nix-flake.yml b/.github/workflows/nix-flake.yml new file mode 100644 index 0000000..a8ddde9 --- /dev/null +++ b/.github/workflows/nix-flake.yml @@ -0,0 +1,33 @@ +name: "CI: Flake check" + +on: + push: + paths: + - "flake.nix" + - "flake.lock" + - ".github/workflows/nix-flake.yml" + - ".github/actions/setup-nix/**" + pull_request: + paths: + - "flake.nix" + - "flake.lock" + - ".github/workflows/nix-flake.yml" + - ".github/actions/setup-nix/**" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + # Check flake syntax and structure + flake-check: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - name: Setup Nix + uses: ./.github/actions/setup-nix + + - name: Check flake + run: nix flake check --all-systems --show-trace diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6519925..03c5fc1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,25 +20,22 @@ jobs: manifest-file: .release-please-manifest.json # Only release to PyPI when a new release is created - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 if: ${{ steps.release.outputs.release_created }} - - name: Install uv + - name: Setup Nix if: ${{ steps.release.outputs.release_created }} - uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1 - with: - python-version: "3.11" - enable-cache: true + uses: ./.github/actions/setup-nix - name: Update version in __init__.py if: ${{ steps.release.outputs.release_created }} - run: | - uv run scripts/update_version.py + run: nix develop --command uv run scripts/update_version.py - name: Build and publish package if: ${{ steps.release.outputs.release_created }} env: UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} run: | - uv build - uv publish + nix develop --command uv build + nix develop --command uv publish diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 57094a9..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Tests - -on: - pull_request: - branches: - - main - -jobs: - test: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.9", "3.10", "3.13"] - include: - - python-version: "3.9" - test-extras: "--all-extras --no-extra mcp" - - python-version: "3.10" - test-extras: "--all-extras" - - python-version: "3.13" - test-extras: "--all-extras" - env: - STACKONE_API_KEY: ${{ secrets.STACKONE_API_KEY }} - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - - name: Install uv - uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1 - with: - python-version: ${{ matrix.python-version }} - enable-cache: true - - - name: Install dependencies - run: uv sync ${{ matrix.test-extras }} - - - name: Run tests - run: uv run pytest diff --git a/.gitignore b/.gitignore index 28a513e..791ec39 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ site/ *.egg-info dist/ build/ + +# Git hooks (managed by Nix) +.pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index a623acc..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,16 +0,0 @@ -repos: - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.6 - hooks: - - id: ruff - args: [--fix] - - id: ruff-format - - - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.8.0 - hooks: - - id: mypy - files: ^stackone_ai/ - additional_dependencies: - - types-requests - - types-PyYAML diff --git a/CLAUDE.md b/CLAUDE.md index 1bf16e7..83d2c23 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -22,7 +22,7 @@ make install # Install dependencies and pre-commit hooks # Code quality make lint # Run ruff linting -make lint-fix # Auto-fix linting issues +make lint-fix # Auto-fix linting issues make mypy # Run type checking # Testing @@ -64,17 +64,20 @@ make mcp-inspector # Run MCP server inspector for debugging ### OpenAPI Specifications All tool definitions are generated from OpenAPI specs in `stackone_ai/oas/`: + - `core.json`, `ats.json`, `crm.json`, `documents.json`, `hris.json`, `iam.json`, `lms.json`, `marketing.json` ## Key Development Patterns ### Tool Filtering + ```python # Use glob patterns for tool selection tools = StackOneToolSet(include_tools=["hris_*", "!hris_create_*"]) ``` ### Authentication + ```python # Uses environment variables or direct configuration toolset = StackOneToolSet( @@ -84,11 +87,13 @@ toolset = StackOneToolSet( ``` ### Type Safety + - Full type annotations required (Python 3.11+) - Strict mypy configuration - Use generics for better IDE support ### Testing + - Snapshot testing for tool parsing (`tests/snapshots/`) - Async tests use `pytest-asyncio` - Example validation: See @./.cursor/rules/examples-standards @@ -105,16 +110,19 @@ toolset = StackOneToolSet( ## Common Tasks ### Adding New SaaS Integration + 1. Add OpenAPI spec to `stackone_ai/oas/` 2. Parser automatically converts to tool definitions 3. Test with `make test-tools` ### Modifying Tool Behavior + - Core execution logic in `StackOneTool.execute()` method - HTTP configuration via `ExecuteConfig` class - Response handling in `_process_response()` ### Updating Documentation + - Examples requirements: See @./.cursor/rules/examples-standards - Run `make docs-serve` to preview changes - MkDocs config in `mkdocs.yml` diff --git a/README.md b/README.md index 3d3c5d3..a822426 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,30 @@ StackOne AI provides a unified interface for accessing various SaaS tools throug ## Installation +### Using Nix (Recommended for Development) + +If you have [Nix](https://nixos.org/) installed with flakes enabled: + +```bash +# Enter development environment (auto-installs dependencies and git hooks) +nix develop + +# Format code +nix fmt + +# Run checks +nix flake check +``` + +The Nix development environment includes: + +- Python with uv package manager +- Automatic dependency installation +- Git hooks (treefmt + mypy) auto-configured +- Consistent environment across all platforms + +### Using pip/uv + ```bash pip install 'stackone-ai[mcp]' @@ -299,6 +323,7 @@ result = feedback_tool.call( ``` **Important**: The AI agent should always ask for user permission before submitting feedback: + - "Are you ok with sending feedback to StackOne? The LLM will take care of sending it." - Only call the tool after the user explicitly agrees. @@ -346,6 +371,7 @@ tools = toolset.fetch_tools(actions=["hris_*"], account_ids=["acc-123"]) ``` Key differences: + - `fetch_tools()` uses keyword arguments for all filtering - `account_id` becomes `account_ids` (list) - Filter patterns go in the `actions` parameter (list) diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..3396f08 --- /dev/null +++ b/flake.lock @@ -0,0 +1,170 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1761588595, + "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1765835352, + "narHash": "sha256-XswHlK/Qtjasvhd1nOa1e8MgZ8GS//jBoTqWtrS1Giw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "a34fae9c08a15ad73f295041fec82323541400a9", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1765464257, + "narHash": "sha256-dixPWKiHzh80PtD0aLuxYNQ0xP+843dfXG/yM3OzaYQ=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "09e45f2598e1a8499c3594fe11ec2943f34fe509", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1764947035, + "narHash": "sha256-EYHSjVM4Ox4lvCXUMiKKs2vETUSL5mx+J2FfutM7T9w=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a672be65651c80d3f592a89b3945466584a22069", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1765674936, + "narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1765772535, + "narHash": "sha256-aq+dQoaPONOSjtFIBnAXseDm9TUhIbe215TPmkfMYww=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "09b8fda8959d761445f12b55f380d90375a1d6bb", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1761236834, + "narHash": "sha256-+pthv6hrL5VLW2UqPdISGuLiUZ6SnAXdd2DdUE+fV2Q=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "d5faa84122bc0a1fd5d378492efce4e289f8eac1", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-parts": "flake-parts", + "git-hooks": "git-hooks", + "nixpkgs": "nixpkgs_2", + "treefmt-nix": "treefmt-nix" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1762938485, + "narHash": "sha256-AlEObg0syDl+Spi4LsZIBrjw+snSVU4T8MOeuZJUJjM=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..7f50eb8 --- /dev/null +++ b/flake.nix @@ -0,0 +1,101 @@ +{ + description = "StackOne AI Python SDK development environment"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-parts.url = "github:hercules-ci/flake-parts"; + git-hooks.url = "github:cachix/git-hooks.nix"; + treefmt-nix.url = "github:numtide/treefmt-nix"; + }; + + outputs = + inputs@{ + flake-parts, + git-hooks, + treefmt-nix, + ... + }: + flake-parts.lib.mkFlake { inherit inputs; } { + systems = [ + "x86_64-linux" + "aarch64-linux" + "aarch64-darwin" + ]; + + imports = [ + git-hooks.flakeModule + treefmt-nix.flakeModule + ]; + + perSystem = + { + config, + pkgs, + ... + }: + { + # Treefmt configuration for formatting + treefmt = { + projectRootFile = "flake.nix"; + programs = { + nixfmt.enable = true; + nixfmt.package = pkgs.nixfmt-rfc-style; + ruff-check.enable = true; + ruff-format.enable = true; + prettier = { + enable = true; + includes = [ + "*.md" + "*.yml" + "*.yaml" + "*.json" + ]; + excludes = [ + "CHANGELOG.md" + ]; + }; + }; + }; + + # Git hooks configuration + pre-commit = { + check.enable = false; # Skip check in flake (mypy needs Python env) + settings.hooks = { + treefmt = { + enable = true; + package = config.treefmt.build.wrapper; + }; + mypy = { + enable = true; + name = "mypy"; + entry = "${pkgs.uv}/bin/uv run mypy"; + files = "^stackone_ai/"; + language = "system"; + types = [ "python" ]; + }; + }; + }; + + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ + uv + just + nixfmt-rfc-style + ]; + + shellHook = '' + echo "StackOne AI Python SDK development environment" + + # Install dependencies only if .venv is missing or uv.lock is newer + if [ ! -d .venv ] || [ uv.lock -nt .venv ]; then + echo "📦 Installing dependencies..." + uv sync --all-extras + fi + + # Install git hooks + ${config.pre-commit.installationScript} + ''; + }; + }; + }; +} diff --git a/Makefile b/justfile similarity index 61% rename from Makefile rename to justfile index 3eb5ba1..8aa9378 100644 --- a/Makefile +++ b/justfile @@ -1,33 +1,42 @@ +# Install dependencies and pre-commit hooks install: uv sync --all-extras - uv run pre-commit install +# Run ruff linting lint: uv run ruff check . +# Auto-fix linting issues lint-fix: uv run ruff check --fix . +# Run all tests test: uv run pytest +# Run tool-specific tests test-tools: uv run pytest tests +# Run example tests test-examples: uv run pytest examples +# Run type checking mypy: uv run mypy stackone_ai +# Build and serve docs locally docs-serve: uv run scripts/build_docs.py uv run mkdocs serve +# Build docs for deployment docs-build: uv run scripts/build_docs.py uv run mkdocs build +# Run MCP server inspector for debugging mcp-inspector: uv sync --all-extras npx @modelcontextprotocol/inspector stackmcp diff --git a/pyproject.toml b/pyproject.toml index af176a0..514ce95 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,7 +66,6 @@ docs = [ [dependency-groups] dev = [ "mypy>=1.15.0", - "pre-commit>=4.1.0", "pytest>=8.3.4", "pytest-asyncio>=0.25.3", "pytest-cov>=6.0.0", diff --git a/stackone_ai/feedback/tool.py b/stackone_ai/feedback/tool.py index 04396b0..d54e438 100644 --- a/stackone_ai/feedback/tool.py +++ b/stackone_ai/feedback/tool.py @@ -120,23 +120,11 @@ def execute( "tool_names": tool_names, } result = super().execute(validated_arguments, options=options) - results.append({ - "account_id": account_id, - "status": "success", - "result": result - }) + results.append({"account_id": account_id, "status": "success", "result": result}) except Exception as exc: error_msg = str(exc) - errors.append({ - "account_id": account_id, - "status": "error", - "error": error_msg - }) - results.append({ - "account_id": account_id, - "status": "error", - "error": error_msg - }) + errors.append({"account_id": account_id, "status": "error", "error": error_msg}) + results.append({"account_id": account_id, "status": "error", "error": error_msg}) # Return combined results return { @@ -144,7 +132,7 @@ def execute( "total_accounts": len(account_ids), "successful": len([r for r in results if r["status"] == "success"]), "failed": len(errors), - "results": results + "results": results, } except json.JSONDecodeError as exc: @@ -176,7 +164,7 @@ def create_feedback_tool( name = "meta_collect_tool_feedback" description = ( "Collects user feedback on StackOne tool performance. " - "First ask the user, \"Are you ok with sending feedback to StackOne?\" " + 'First ask the user, "Are you ok with sending feedback to StackOne?" ' "and mention that the LLM will take care of sending it. " "Call this tool only when the user explicitly answers yes." ) diff --git a/stackone_ai/meta_tools.py b/stackone_ai/meta_tools.py index fb211b6..f2f0b69 100644 --- a/stackone_ai/meta_tools.py +++ b/stackone_ai/meta_tools.py @@ -28,9 +28,7 @@ class MetaToolSearchResult(BaseModel): class ToolIndex: """Hybrid BM25 + TF-IDF tool search index""" - def __init__( - self, tools: list[StackOneTool], hybrid_alpha: float | None = None - ) -> None: + def __init__(self, tools: list[StackOneTool], hybrid_alpha: float | None = None) -> None: """Initialize tool index with hybrid search Args: diff --git a/uv.lock b/uv.lock index e701d45..8390f0b 100644 --- a/uv.lock +++ b/uv.lock @@ -469,15 +469,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/8f/a1e836f82d8e32a97e6b29cc8f641779181ac7363734f12df27db803ebda/cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9", size = 182794, upload-time = "2025-09-08T23:24:02.943Z" }, ] -[[package]] -name = "cfgv" -version = "3.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, -] - [[package]] name = "charset-normalizer" version = "3.4.4" @@ -1027,15 +1018,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550, upload-time = "2023-08-31T06:11:58.822Z" }, ] -[[package]] -name = "distlib" -version = "0.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, -] - [[package]] name = "distro" version = "1.9.0" @@ -1102,27 +1084,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, ] -[[package]] -name = "filelock" -version = "3.19.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" }, -] - [[package]] name = "filelock" version = "3.20.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.13'", - "python_full_version >= '3.11' and python_full_version < '3.13'", - "python_full_version == '3.10.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" }, @@ -1508,7 +1473,7 @@ name = "huggingface-hub" version = "0.35.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "filelock", version = "3.20.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "filelock", marker = "python_full_version >= '3.10'" }, { name = "fsspec", marker = "python_full_version >= '3.10'" }, { name = "hf-xet", marker = "(python_full_version >= '3.10' and platform_machine == 'aarch64') or (python_full_version >= '3.10' and platform_machine == 'amd64') or (python_full_version >= '3.10' and platform_machine == 'arm64') or (python_full_version >= '3.10' and platform_machine == 'x86_64')" }, { name = "packaging", marker = "python_full_version >= '3.10'" }, @@ -1534,15 +1499,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f0/0f/310fb31e39e2d734ccaa2c0fb981ee41f7bd5056ce9bc29b2248bd569169/humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477", size = 86794, upload-time = "2021-09-17T21:40:39.897Z" }, ] -[[package]] -name = "identify" -version = "2.6.15" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311, upload-time = "2025-10-02T17:43:40.631Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183, upload-time = "2025-10-02T17:43:39.137Z" }, -] - [[package]] name = "idna" version = "3.11" @@ -2624,15 +2580,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec", size = 2034406, upload-time = "2025-05-29T11:35:04.961Z" }, ] -[[package]] -name = "nodeenv" -version = "1.9.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, -] - [[package]] name = "numpy" version = "2.0.2" @@ -3405,22 +3352,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4f/98/e480cab9a08d1c09b1c59a93dade92c1bb7544826684ff2acbfd10fcfbd4/posthog-5.4.0-py3-none-any.whl", hash = "sha256:284dfa302f64353484420b52d4ad81ff5c2c2d1d607c4e2db602ac72761831bd", size = 105364, upload-time = "2025-06-20T23:19:22.001Z" }, ] -[[package]] -name = "pre-commit" -version = "4.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cfgv" }, - { name = "identify" }, - { name = "nodeenv" }, - { name = "pyyaml" }, - { name = "virtualenv" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ff/29/7cf5bbc236333876e4b41f56e06857a87937ce4bf91e117a6991a2dbb02a/pre_commit-4.3.0.tar.gz", hash = "sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16", size = 193792, upload-time = "2025-08-09T18:56:14.651Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/a5/987a405322d78a73b66e39e4a90e4ef156fd7141bf71df987e50717c321b/pre_commit-4.3.0-py2.py3-none-any.whl", hash = "sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8", size = 220965, upload-time = "2025-08-09T18:56:13.192Z" }, -] - [[package]] name = "prompt-toolkit" version = "3.0.52" @@ -4928,7 +4859,6 @@ mcp = [ [package.dev-dependencies] dev = [ { name = "mypy" }, - { name = "pre-commit" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-cov" }, @@ -4963,7 +4893,6 @@ provides-extras = ["mcp", "examples", "docs"] [package.metadata.requires-dev] dev = [ { name = "mypy", specifier = ">=1.15.0" }, - { name = "pre-commit", specifier = ">=4.1.0" }, { name = "pytest", specifier = ">=8.3.4" }, { name = "pytest-asyncio", specifier = ">=0.25.3" }, { name = "pytest-cov", specifier = ">=6.0.0" }, @@ -5326,23 +5255,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1a/5c/6ba221bb60f1e6474474102e17e38612ec7a06dc320e22b687ab563d877f/uvloop-0.21.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2d1f581393673ce119355d56da84fe1dd9d2bb8b3d13ce792524e1607139feff", size = 3804696, upload-time = "2024-10-14T23:38:33.633Z" }, ] -[[package]] -name = "virtualenv" -version = "20.35.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "distlib" }, - { name = "filelock", version = "3.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "filelock", version = "3.20.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "platformdirs", version = "4.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a4/d5/b0ccd381d55c8f45d46f77df6ae59fbc23d19e901e2d523395598e5f4c93/virtualenv-20.35.3.tar.gz", hash = "sha256:4f1a845d131133bdff10590489610c98c168ff99dc75d6c96853801f7f67af44", size = 6002907, upload-time = "2025-10-10T21:23:33.178Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/73/d9a94da0e9d470a543c1b9d3ccbceb0f59455983088e727b8a1824ed90fb/virtualenv-20.35.3-py3-none-any.whl", hash = "sha256:63d106565078d8c8d0b206d48080f938a8b25361e19432d2c9db40d2899c810a", size = 5981061, upload-time = "2025-10-10T21:23:30.433Z" }, -] - [[package]] name = "watchdog" version = "6.0.0"