diff --git a/.github/workflows/feature-launcher.yml b/.github/workflows/feature-launcher.yml new file mode 100644 index 00000000..f21d1b98 --- /dev/null +++ b/.github/workflows/feature-launcher.yml @@ -0,0 +1,24 @@ +name: Automate Engineering Feature Release Campaigns + +on: + issues: + types: [labeled] + +jobs: + notify-discord: + if: github.event.label.name == 'feature-release' + runs-on: ubuntu-latest + steps: + - name: Send Feature Release Notification to Discord + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} + ISSUE_TITLE: ${{ github.event.issue.title }} + ISSUE_BODY: ${{ github.event.issue.body }} + ISSUE_URL: ${{ github.event.issue.html_url }} + run: | + curl -H "Content-Type: application/json" \ + -X POST \ + -d '{ + "content": "**š New Feature Launched!**\n\nš *${{ env.ISSUE_TITLE }}* is now available to try!\nš Description: ${{ env.ISSUE_BODY }}\nš [Check it out here](${{ env.ISSUE_URL }})" + }' \ + $DISCORD_WEBHOOK diff --git a/.github/workflows/image-build.yml b/.github/workflows/image-build.yml index 8f043213..ec553285 100644 --- a/.github/workflows/image-build.yml +++ b/.github/workflows/image-build.yml @@ -8,6 +8,10 @@ on: description: 'The name of the artifact to upload' required: true type: string + platform: + description: 'The platform to build the image for' + required: true + type: string permissions: contents: read @@ -22,6 +26,10 @@ jobs: steps: - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - name: Set up QEMU for cross-platform builds + # Only set up QEMU if the platform is not linux/amd64 + if: ${{ inputs.platform != 'linux/amd64' }} + uses: docker/setup-qemu-action@4574d27a4764455b42196d70a065bc6853246a25 # v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3 - name: Download artifact @@ -43,13 +51,13 @@ jobs: run: | git lfs install git lfs pull - - name: Test build on x86 + - name: Test build - ${{ inputs.platform }} id: docker_build uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v5 with: context: . file: ./Dockerfile - platforms: linux/amd64 + platforms: ${{ inputs.platform }} push: false # Only attempt to build, to verify the Dockerfile is working load: true cache-from: type=gha @@ -58,12 +66,16 @@ jobs: LATEST_RELEASE=${{ env.LATEST_RELEASE }} tags: ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} - name: Save Docker image as a tarball + # Only save the image if the build was for linux/amd64, as we only need it for the integration tests + if: ${{ inputs.platform == 'linux/amd64' }} run: | # List all images docker images # Save the image as a tarball docker save -o image.tar ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} - name: Upload Docker image artifact + # Only upload the image if the build was for linux/amd64, as we only need it for the integration tests + if: ${{ inputs.platform == 'linux/amd64' }} uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4 with: name: ${{ inputs.artifact-name }} diff --git a/.github/workflows/import_packages.yml b/.github/workflows/import_packages.yml index 7c519724..cd56c7e7 100644 --- a/.github/workflows/import_packages.yml +++ b/.github/workflows/import_packages.yml @@ -31,7 +31,7 @@ jobs: git lfs pull - name: Configure AWS Credentials for S3 - uses: aws-actions/configure-aws-credentials@49f33fe638c0cba4fb16037a27915a7ab7740259 + uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 with: role-to-assume: ${{ secrets.AWS_ROLE_INSIGHT_DATA_IMPORT }} aws-region: ${{ env.AWS_REGION }} diff --git a/.github/workflows/run-on-pr.yml b/.github/workflows/run-on-pr.yml index 5d55be54..fc942421 100644 --- a/.github/workflows/run-on-pr.yml +++ b/.github/workflows/run-on-pr.yml @@ -14,10 +14,17 @@ jobs: name: Build, Test & Lint uses: ./.github/workflows/ci.yml image-build: - name: OCI Image - Build + name: OCI Image - Build x86 uses: ./.github/workflows/image-build.yml with: artifact-name: "codegate-image" + platform: "linux/amd64" + image-build-arm64: + name: OCI Image - Build ARM64 + uses: ./.github/workflows/image-build.yml + with: + artifact-name: "codegate-image" + platform: "linux/arm64" integration-tests: if: github.event.pull_request.head.repo.full_name == 'stacklok/codegate' name: Integration Tests diff --git a/.github/workflows/run-on-push.yml b/.github/workflows/run-on-push.yml index 6443f898..5db82792 100644 --- a/.github/workflows/run-on-push.yml +++ b/.github/workflows/run-on-push.yml @@ -14,10 +14,17 @@ jobs: name: Build, Test & Lint uses: ./.github/workflows/ci.yml image-build: - name: OCI Image - Build + name: OCI Image - Build x86 uses: ./.github/workflows/image-build.yml with: artifact-name: "codegate-image" + platform: "linux/amd64" + image-build-arm64: + name: OCI Image - Build ARM64 + uses: ./.github/workflows/image-build.yml + with: + artifact-name: "codegate-image" + platform: "linux/arm64" integration-tests: name: Integration Tests needs: [ci, image-build] # We need the image available in order to run the integration tests diff --git a/Dockerfile b/Dockerfile index a20d1be4..0cf87ec1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Builder stage: Install dependencies and build the application -FROM python:3.12-slim AS builder +FROM docker.io/library/python:3.12-slim@sha256:34656cd90456349040784165b9decccbcee4de66f3ead0a1168ba893455afd1e AS builder ARG CODEGATE_VERSION=dev @@ -27,7 +27,7 @@ COPY . /app RUN sed -i "s/_VERSION =.*/_VERSION = \"${CODEGATE_VERSION}\"/g" /app/src/codegate/__init__.py # Build the webapp -FROM node:23-slim AS webbuilder +FROM docker.io/library/node:23-slim@sha256:f498ea1bec900d539ddba9ae881bf5f69d9052fdefc28e50479b85e284fac54c AS webbuilder diff --git a/docs/development.md b/docs/development.md index 3f7668d9..c1591b6e 100644 --- a/docs/development.md +++ b/docs/development.md @@ -59,6 +59,19 @@ To install all dependencies for your local development environment, run npm install ``` +Note that if you are running some processes (specifically the package import +script) on macOS, you will need a Python build linked against sqlite installed +from Homebrew. macOS ships with sqlite, but it lacks some required +functionality. This can be accomplished with: + +``` +# substitute for your version of choice +PYTHON_VERSION=3.12.9 +brew install sqlite +LDFLAGS="-L$(brew --prefix sqlite)/lib" CPPFLAGS="-I$(brew --prefix sqlite)/include" PYTHON_CONFIGURE_OPTS="--enable-loadable-sqlite-extensions" pyenv install -v $PYTHON_VERSION +poetry env use $PYTHON_VERSION +``` + ### Running the development server Run the development server using: diff --git a/model_cost_data/model_prices_and_context_window.json b/model_cost_data/model_prices_and_context_window.json index 62cd79a6..5eec1fcf 100644 --- a/model_cost_data/model_prices_and_context_window.json +++ b/model_cost_data/model_prices_and_context_window.json @@ -1412,6 +1412,19 @@ "deprecation_date": "2025-03-31", "supports_tool_choice": true }, + "azure/gpt-3.5-turbo-0125": { + "max_tokens": 4096, + "max_input_tokens": 16384, + "max_output_tokens": 4096, + "input_cost_per_token": 0.0000005, + "output_cost_per_token": 0.0000015, + "litellm_provider": "azure", + "mode": "chat", + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "deprecation_date": "2025-03-31", + "supports_tool_choice": true + }, "azure/gpt-35-turbo-16k": { "max_tokens": 4096, "max_input_tokens": 16385, @@ -1433,6 +1446,17 @@ "supports_function_calling": true, "supports_tool_choice": true }, + "azure/gpt-3.5-turbo": { + "max_tokens": 4096, + "max_input_tokens": 4097, + "max_output_tokens": 4096, + "input_cost_per_token": 0.0000005, + "output_cost_per_token": 0.0000015, + "litellm_provider": "azure", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true + }, "azure/gpt-3.5-turbo-instruct-0914": { "max_tokens": 4097, "max_input_tokens": 4097, @@ -3634,6 +3658,42 @@ "source": "https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models#foundation_models", "supports_tool_choice": true }, + "gemini-2.0-pro-exp-02-05": { + "max_tokens": 8192, + "max_input_tokens": 2097152, + "max_output_tokens": 8192, + "max_images_per_prompt": 3000, + "max_videos_per_prompt": 10, + "max_video_length": 1, + "max_audio_length_hours": 8.4, + "max_audio_per_prompt": 1, + "max_pdf_size_mb": 30, + "input_cost_per_image": 0, + "input_cost_per_video_per_second": 0, + "input_cost_per_audio_per_second": 0, + "input_cost_per_token": 0, + "input_cost_per_character": 0, + "input_cost_per_token_above_128k_tokens": 0, + "input_cost_per_character_above_128k_tokens": 0, + "input_cost_per_image_above_128k_tokens": 0, + "input_cost_per_video_per_second_above_128k_tokens": 0, + "input_cost_per_audio_per_second_above_128k_tokens": 0, + "output_cost_per_token": 0, + "output_cost_per_character": 0, + "output_cost_per_token_above_128k_tokens": 0, + "output_cost_per_character_above_128k_tokens": 0, + "litellm_provider": "vertex_ai-language-models", + "mode": "chat", + "supports_system_messages": true, + "supports_function_calling": true, + "supports_vision": true, + "supports_audio_input": true, + "supports_video_input": true, + "supports_pdf_input": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "source": "https://cloud.google.com/vertex-ai/generative-ai/pricing" + }, "gemini-2.0-flash-exp": { "max_tokens": 8192, "max_input_tokens": 1048576, @@ -7035,7 +7095,9 @@ "input_cost_per_token": 0.00000072, "output_cost_per_token": 0.00000072, "litellm_provider": "bedrock_converse", - "mode": "chat" + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": false }, "meta.llama2-13b-chat-v1": { "max_tokens": 4096, @@ -7375,6 +7437,17 @@ "supports_function_calling": true, "supports_tool_choice": false }, + "us.meta.llama3-3-70b-instruct-v1:0": { + "max_tokens": 4096, + "max_input_tokens": 128000, + "max_output_tokens": 4096, + "input_cost_per_token": 0.00000072, + "output_cost_per_token": 0.00000072, + "litellm_provider": "bedrock_converse", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": false + }, "512-x-512/50-steps/stability.stable-diffusion-xl-v0": { "max_tokens": 77, "max_input_tokens": 77, @@ -8084,8 +8157,7 @@ "input_cost_per_token": 0.00000035, "output_cost_per_token": 0.00000140, "litellm_provider": "perplexity", - "mode": "chat" , - "supports_tool_choice": true + "mode": "chat" }, "perplexity/codellama-70b-instruct": { "max_tokens": 16384, @@ -8094,8 +8166,7 @@ "input_cost_per_token": 0.00000070, "output_cost_per_token": 0.00000280, "litellm_provider": "perplexity", - "mode": "chat" , - "supports_tool_choice": true + "mode": "chat" }, "perplexity/llama-3.1-70b-instruct": { "max_tokens": 131072, @@ -8104,8 +8175,7 @@ "input_cost_per_token": 0.000001, "output_cost_per_token": 0.000001, "litellm_provider": "perplexity", - "mode": "chat" , - "supports_tool_choice": true + "mode": "chat" }, "perplexity/llama-3.1-8b-instruct": { "max_tokens": 131072, @@ -8114,8 +8184,7 @@ "input_cost_per_token": 0.0000002, "output_cost_per_token": 0.0000002, "litellm_provider": "perplexity", - "mode": "chat" , - "supports_tool_choice": true + "mode": "chat" }, "perplexity/llama-3.1-sonar-huge-128k-online": { "max_tokens": 127072, @@ -8125,8 +8194,7 @@ "output_cost_per_token": 0.000005, "litellm_provider": "perplexity", "mode": "chat", - "deprecation_date": "2025-02-22", - "supports_tool_choice": true + "deprecation_date": "2025-02-22" }, "perplexity/llama-3.1-sonar-large-128k-online": { "max_tokens": 127072, @@ -8136,8 +8204,7 @@ "output_cost_per_token": 0.000001, "litellm_provider": "perplexity", "mode": "chat", - "deprecation_date": "2025-02-22", - "supports_tool_choice": true + "deprecation_date": "2025-02-22" }, "perplexity/llama-3.1-sonar-large-128k-chat": { "max_tokens": 131072, @@ -8147,8 +8214,7 @@ "output_cost_per_token": 0.000001, "litellm_provider": "perplexity", "mode": "chat", - "deprecation_date": "2025-02-22", - "supports_tool_choice": true + "deprecation_date": "2025-02-22" }, "perplexity/llama-3.1-sonar-small-128k-chat": { "max_tokens": 131072, @@ -8158,8 +8224,7 @@ "output_cost_per_token": 0.0000002, "litellm_provider": "perplexity", "mode": "chat", - "deprecation_date": "2025-02-22", - "supports_tool_choice": true + "deprecation_date": "2025-02-22" }, "perplexity/llama-3.1-sonar-small-128k-online": { "max_tokens": 127072, @@ -8169,8 +8234,43 @@ "output_cost_per_token": 0.0000002, "litellm_provider": "perplexity", "mode": "chat" , - "deprecation_date": "2025-02-22", - "supports_tool_choice": true + "deprecation_date": "2025-02-22" + }, + "perplexity/sonar": { + "max_tokens": 127072, + "max_input_tokens": 127072, + "max_output_tokens": 127072, + "input_cost_per_token": 0.000001, + "output_cost_per_token": 0.000001, + "litellm_provider": "perplexity", + "mode": "chat" + }, + "perplexity/sonar-pro": { + "max_tokens": 200000, + "max_input_tokens": 200000, + "max_output_tokens": 8096, + "input_cost_per_token": 0.000003, + "output_cost_per_token": 0.000015, + "litellm_provider": "perplexity", + "mode": "chat" + }, + "perplexity/sonar": { + "max_tokens": 127072, + "max_input_tokens": 127072, + "max_output_tokens": 127072, + "input_cost_per_token": 0.000001, + "output_cost_per_token": 0.000001, + "litellm_provider": "perplexity", + "mode": "chat" + }, + "perplexity/sonar-pro": { + "max_tokens": 200000, + "max_input_tokens": 200000, + "max_output_tokens": 8096, + "input_cost_per_token": 0.000003, + "output_cost_per_token": 0.000015, + "litellm_provider": "perplexity", + "mode": "chat" }, "perplexity/pplx-7b-chat": { "max_tokens": 8192, @@ -8179,8 +8279,7 @@ "input_cost_per_token": 0.00000007, "output_cost_per_token": 0.00000028, "litellm_provider": "perplexity", - "mode": "chat" , - "supports_tool_choice": true + "mode": "chat" }, "perplexity/pplx-70b-chat": { "max_tokens": 4096, @@ -8189,8 +8288,7 @@ "input_cost_per_token": 0.00000070, "output_cost_per_token": 0.00000280, "litellm_provider": "perplexity", - "mode": "chat" , - "supports_tool_choice": true + "mode": "chat" }, "perplexity/pplx-7b-online": { "max_tokens": 4096, @@ -8200,8 +8298,7 @@ "output_cost_per_token": 0.00000028, "input_cost_per_request": 0.005, "litellm_provider": "perplexity", - "mode": "chat" , - "supports_tool_choice": true + "mode": "chat" }, "perplexity/pplx-70b-online": { "max_tokens": 4096, @@ -8211,8 +8308,7 @@ "output_cost_per_token": 0.00000280, "input_cost_per_request": 0.005, "litellm_provider": "perplexity", - "mode": "chat" , - "supports_tool_choice": true + "mode": "chat" }, "perplexity/llama-2-70b-chat": { "max_tokens": 4096, @@ -8221,8 +8317,7 @@ "input_cost_per_token": 0.00000070, "output_cost_per_token": 0.00000280, "litellm_provider": "perplexity", - "mode": "chat" , - "supports_tool_choice": true + "mode": "chat" }, "perplexity/mistral-7b-instruct": { "max_tokens": 4096, @@ -8231,8 +8326,7 @@ "input_cost_per_token": 0.00000007, "output_cost_per_token": 0.00000028, "litellm_provider": "perplexity", - "mode": "chat" , - "supports_tool_choice": true + "mode": "chat" }, "perplexity/mixtral-8x7b-instruct": { "max_tokens": 4096, @@ -8241,8 +8335,7 @@ "input_cost_per_token": 0.00000007, "output_cost_per_token": 0.00000028, "litellm_provider": "perplexity", - "mode": "chat", - "supports_tool_choice": true + "mode": "chat" }, "perplexity/sonar-small-chat": { "max_tokens": 16384, @@ -8251,8 +8344,7 @@ "input_cost_per_token": 0.00000007, "output_cost_per_token": 0.00000028, "litellm_provider": "perplexity", - "mode": "chat", - "supports_tool_choice": true + "mode": "chat" }, "perplexity/sonar-small-online": { "max_tokens": 12000, @@ -8262,8 +8354,7 @@ "output_cost_per_token": 0.00000028, "input_cost_per_request": 0.005, "litellm_provider": "perplexity", - "mode": "chat", - "supports_tool_choice": true + "mode": "chat" }, "perplexity/sonar-medium-chat": { "max_tokens": 16384, @@ -8272,8 +8363,7 @@ "input_cost_per_token": 0.0000006, "output_cost_per_token": 0.0000018, "litellm_provider": "perplexity", - "mode": "chat", - "supports_tool_choice": true + "mode": "chat" }, "perplexity/sonar-medium-online": { "max_tokens": 12000, @@ -8283,8 +8373,7 @@ "output_cost_per_token": 0.0000018, "input_cost_per_request": 0.005, "litellm_provider": "perplexity", - "mode": "chat", - "supports_tool_choice": true + "mode": "chat" }, "fireworks_ai/accounts/fireworks/models/llama-v3p2-1b-instruct": { "max_tokens": 16384, @@ -9044,4 +9133,4 @@ "output_cost_per_second": 0.00, "litellm_provider": "assemblyai" } -} \ No newline at end of file +} diff --git a/poetry.lock b/poetry.lock index 27ec43ce..6f4d89cc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -6,7 +6,6 @@ version = "2.4.6" description = "Happy Eyeballs for asyncio" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "aiohappyeyeballs-2.4.6-py3-none-any.whl", hash = "sha256:147ec992cf873d74f5062644332c539fcd42956dc69453fe5204195e560517e1"}, {file = "aiohappyeyeballs-2.4.6.tar.gz", hash = "sha256:9b05052f9042985d32ecbe4b59a77ae19c006a78f1344d7fdad69d28ded3d0b0"}, @@ -18,7 +17,6 @@ version = "3.11.12" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aa8a8caca81c0a3e765f19c6953416c58e2f4cc1b84829af01dd1c771bb2f91f"}, {file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84ede78acde96ca57f6cf8ccb8a13fbaf569f6011b9a52f870c662d4dc8cd854"}, @@ -121,7 +119,6 @@ version = "1.3.2" description = "aiosignal: a list of registered asynchronous callbacks" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, @@ -136,7 +133,6 @@ version = "0.21.0" description = "asyncio bridge to the standard sqlite3 module" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "aiosqlite-0.21.0-py3-none-any.whl", hash = "sha256:2549cf4057f95f53dcba16f2b64e8e2791d7e1adedb13197dd8ed77bb226d7d0"}, {file = "aiosqlite-0.21.0.tar.gz", hash = "sha256:131bb8056daa3bc875608c631c678cda73922a2d4ba8aec373b19f18c17e7aa3"}, @@ -155,7 +151,6 @@ version = "1.14.1" description = "A database migration tool for SQLAlchemy." optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "alembic-1.14.1-py3-none-any.whl", hash = "sha256:1acdd7a3a478e208b0503cd73614d5e4c6efafa4e73518bb60e4f2846a37b1c5"}, {file = "alembic-1.14.1.tar.gz", hash = "sha256:496e888245a53adf1498fcab31713a469c65836f8de76e01399aa1c3e90dd213"}, @@ -175,7 +170,6 @@ version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -187,7 +181,6 @@ version = "4.8.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, @@ -209,7 +202,6 @@ version = "25.1.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"}, {file = "attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e"}, @@ -229,7 +221,6 @@ version = "1.32.0" description = "Microsoft Azure Core Library for Python" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "azure_core-1.32.0-py3-none-any.whl", hash = "sha256:eac191a0efb23bfa83fddf321b27b122b4ec847befa3091fa736a5c32c50d7b4"}, {file = "azure_core-1.32.0.tar.gz", hash = "sha256:22b3c35d6b2dae14990f6c1be2912bf23ffe50b220e708a28ab1bb92b1c730e5"}, @@ -245,14 +236,13 @@ aio = ["aiohttp (>=3.0)"] [[package]] name = "bandit" -version = "1.8.2" +version = "1.8.3" description = "Security oriented static analyser for python code." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ - {file = "bandit-1.8.2-py3-none-any.whl", hash = "sha256:df6146ad73dd30e8cbda4e29689ddda48364e36ff655dbfc86998401fcf1721f"}, - {file = "bandit-1.8.2.tar.gz", hash = "sha256:e00ad5a6bc676c0954669fe13818024d66b70e42cf5adb971480cf3b671e835f"}, + {file = "bandit-1.8.3-py3-none-any.whl", hash = "sha256:28f04dc0d258e1dd0f99dee8eefa13d1cb5e3fde1a5ab0c523971f97b289bcd8"}, + {file = "bandit-1.8.3.tar.gz", hash = "sha256:f5847beb654d309422985c36644649924e0ea4425c76dec2e89110b87506193a"}, ] [package.dependencies] @@ -274,7 +264,6 @@ version = "25.1.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "black-25.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759e7ec1e050a15f89b770cefbf91ebee8917aac5c20483bc2d80a6c3a04df32"}, {file = "black-25.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e519ecf93120f34243e6b0054db49c00a35f84f195d5bce7e9f5cfc578fc2da"}, @@ -319,7 +308,6 @@ version = "0.7.11" description = "The Blis BLAS-like linear algebra library, as a self-contained C-extension." optional = false python-versions = "*" -groups = ["main"] files = [ {file = "blis-0.7.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cd5fba34c5775e4c440d80e4dea8acb40e2d3855b546e07c4e21fad8f972404c"}, {file = "blis-0.7.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:31273d9086cab9c56986d478e3ed6da6752fa4cdd0f7b5e8e5db30827912d90d"}, @@ -366,7 +354,6 @@ version = "1.2.2.post1" description = "A simple, correct Python build frontend" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "build-1.2.2.post1-py3-none-any.whl", hash = "sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5"}, {file = "build-1.2.2.post1.tar.gz", hash = "sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7"}, @@ -390,7 +377,6 @@ version = "5.5.1" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "cachetools-5.5.1-py3-none-any.whl", hash = "sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb"}, {file = "cachetools-5.5.1.tar.gz", hash = "sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95"}, @@ -402,7 +388,6 @@ version = "2.0.10" description = "Super lightweight function registries for your library" optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "catalogue-2.0.10-py3-none-any.whl", hash = "sha256:58c2de0020aa90f4a2da7dfad161bf7b3b054c86a5f09fcedc0b2b740c109a9f"}, {file = "catalogue-2.0.10.tar.gz", hash = "sha256:4f56daa940913d3f09d589c191c74e5a6d51762b3a9e37dd53b7437afd6cda15"}, @@ -414,7 +399,6 @@ version = "2025.1.31" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" -groups = ["main", "dev"] files = [ {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, @@ -426,8 +410,6 @@ version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" -groups = ["main"] -markers = "platform_python_implementation != \"PyPy\"" files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -507,7 +489,6 @@ version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, @@ -609,7 +590,6 @@ version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, @@ -624,7 +604,6 @@ version = "0.20.0" description = "pathlib-style classes for cloud storage services." optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "cloudpathlib-0.20.0-py3-none-any.whl", hash = "sha256:7af3bcefbf73392ae7f31c08b3660ec31607f8c01b7f6262d4d73469a845f641"}, {file = "cloudpathlib-0.20.0.tar.gz", hash = "sha256:f6ef7ca409a510f7ba4639ba50ab3fc5b6dee82d6dff0d7f5715fd0c9ab35891"}, @@ -642,12 +621,10 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main", "dev"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -markers = {main = "sys_platform == \"win32\" or platform_system == \"Windows\"", dev = "platform_system == \"Windows\" or sys_platform == \"win32\" or os_name == \"nt\""} [[package]] name = "coloredlogs" @@ -655,7 +632,6 @@ version = "15.0.1" description = "Colored terminal output for Python's logging module" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -groups = ["main"] files = [ {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"}, {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"}, @@ -673,7 +649,6 @@ version = "0.1.5" description = "The sweetest config system for Python" optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "confection-0.1.5-py3-none-any.whl", hash = "sha256:e29d3c3f8eac06b3f77eb9dfb4bf2fc6bcc9622a98ca00a698e3d019c6430b14"}, {file = "confection-0.1.5.tar.gz", hash = "sha256:8e72dd3ca6bd4f48913cd220f10b8275978e740411654b6e8ca6d7008c590f0e"}, @@ -689,7 +664,6 @@ version = "7.6.12" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "coverage-7.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8"}, {file = "coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879"}, @@ -765,7 +739,6 @@ version = "44.0.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" -groups = ["main"] files = [ {file = "cryptography-44.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf688f615c29bfe9dfc44312ca470989279f0e94bb9f631f85e3459af8efc009"}, {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f"}, @@ -819,7 +792,6 @@ version = "2.0.11" description = "Manage calls to calloc/free through Cython" optional = false python-versions = "*" -groups = ["main"] files = [ {file = "cymem-2.0.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1b4dd8f8c2475c7c9948eefa89c790d83134600858d8d43b90276efd8df3882e"}, {file = "cymem-2.0.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d46ba0d2e0f749195297d16f2286b55af7d7c084db2b853fdfccece2c000c5dc"}, @@ -865,7 +837,6 @@ version = "5.6.3" description = "Disk Cache -- Disk and file backed persistent cache." optional = false python-versions = ">=3" -groups = ["main", "dev"] files = [ {file = "diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19"}, {file = "diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc"}, @@ -877,7 +848,6 @@ version = "1.9.0" description = "Distro - an OS platform information API" optional = false python-versions = ">=3.6" -groups = ["main", "dev"] files = [ {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, @@ -889,7 +859,6 @@ version = "3.8.0" description = "English pipeline optimized for CPU. Components: tok2vec, tagger, parser, senter, ner, attribute_ruler, lemmatizer." optional = false python-versions = "*" -groups = ["main"] files = [ {file = "en_core_web_sm-3.8.0-py3-none-any.whl", hash = "sha256:1932429db727d4bff3deed6b34cfc05df17794f4a52eeb26cf8928f7c1a0fb85"}, ] @@ -904,7 +873,6 @@ version = "0.115.8" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "fastapi-0.115.8-py3-none-any.whl", hash = "sha256:753a96dd7e036b34eeef8babdfcfe3f28ff79648f86551eb36bfc1b0bf4a8cbf"}, {file = "fastapi-0.115.8.tar.gz", hash = "sha256:0ce9111231720190473e222cdf0f07f7206ad7e53ea02beb1d2dc36e2f0741e9"}, @@ -925,7 +893,6 @@ version = "3.17.0" description = "A platform independent file lock." optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338"}, {file = "filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e"}, @@ -942,7 +909,6 @@ version = "25.2.10" description = "The FlatBuffers serialization format for Python" optional = false python-versions = "*" -groups = ["main"] files = [ {file = "flatbuffers-25.2.10-py2.py3-none-any.whl", hash = "sha256:ebba5f4d5ea615af3f7fd70fc310636fbb2bbd1f566ac0a23d98dd412de50051"}, {file = "flatbuffers-25.2.10.tar.gz", hash = "sha256:97e451377a41262f8d9bd4295cc836133415cc03d8cb966410a4af92eb00d26e"}, @@ -954,7 +920,6 @@ version = "1.5.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, @@ -1056,7 +1021,6 @@ version = "2025.2.0" description = "File-system specification" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "fsspec-2025.2.0-py3-none-any.whl", hash = "sha256:9de2ad9ce1f85e1931858535bc882543171d197001a0a5eb2ddc04f1781ab95b"}, {file = "fsspec-2025.2.0.tar.gz", hash = "sha256:1c24b16eaa0a1798afa0337aa0db9b256718ab2a89c425371f5628d22c3b6afd"}, @@ -1096,7 +1060,6 @@ version = "3.1.1" description = "Lightweight in-process concurrent programming" optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"}, {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"}, @@ -1183,7 +1146,6 @@ version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, @@ -1195,7 +1157,6 @@ version = "1.0.7" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, @@ -1217,7 +1178,6 @@ version = "0.28.1" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, @@ -1242,7 +1202,6 @@ version = "0.28.1" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" optional = false python-versions = ">=3.8.0" -groups = ["main", "dev"] files = [ {file = "huggingface_hub-0.28.1-py3-none-any.whl", hash = "sha256:aa6b9a3ffdae939b72c464dbb0d7f99f56e649b55c3d52406f49e0a5a620c0a7"}, {file = "huggingface_hub-0.28.1.tar.gz", hash = "sha256:893471090c98e3b6efbdfdacafe4052b20b84d59866fb6f54c33d9af18c303ae"}, @@ -1277,7 +1236,6 @@ version = "10.0" description = "Human friendly output for text interfaces using Python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -groups = ["main"] files = [ {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"}, {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"}, @@ -1292,7 +1250,6 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" -groups = ["main", "dev"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -1307,7 +1264,6 @@ version = "8.6.1" description = "Read metadata from Python packages" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"}, {file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"}, @@ -1331,7 +1287,6 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -1343,7 +1298,6 @@ version = "3.1.5" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, @@ -1361,7 +1315,6 @@ version = "0.8.2" description = "Fast iterable JSON parser." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "jiter-0.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ca8577f6a413abe29b079bc30f907894d7eb07a865c4df69475e868d73e71c7b"}, {file = "jiter-0.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b25bd626bde7fb51534190c7e3cb97cee89ee76b76d7585580e22f34f5e3f393"}, @@ -1447,7 +1400,6 @@ version = "1.4.2" description = "Lightweight pipelining with Python functions" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6"}, {file = "joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e"}, @@ -1459,7 +1411,6 @@ version = "4.23.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, @@ -1481,7 +1432,6 @@ version = "2024.10.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"}, {file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"}, @@ -1496,7 +1446,6 @@ version = "3.5.0" description = "Tools for labeling human languages with IETF language tags" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "langcodes-3.5.0-py3-none-any.whl", hash = "sha256:853c69d1a35e0e13da2f427bb68fb2fa4a8f4fb899e0c62ad8df8d073dcfed33"}, {file = "langcodes-3.5.0.tar.gz", hash = "sha256:1eef8168d07e51e131a2497ffecad4b663f6208e7c3ae3b8dc15c51734a6f801"}, @@ -1515,7 +1464,6 @@ version = "1.3.0" description = "Supplementary data about languages used by the langcodes module" optional = false python-versions = "*" -groups = ["main"] files = [ {file = "language_data-1.3.0-py3-none-any.whl", hash = "sha256:e2ee943551b5ae5f89cd0e801d1fc3835bb0ef5b7e9c3a4e8e17b2b214548fbf"}, {file = "language_data-1.3.0.tar.gz", hash = "sha256:7600ef8aa39555145d06c89f0c324bf7dab834ea0b0a439d8243762e3ebad7ec"}, @@ -1534,7 +1482,6 @@ version = "2.6.2" description = "Fork of the standard library cgi and cgitb modules, being deprecated in PEP-594" optional = false python-versions = ">=3.10" -groups = ["main"] files = [ {file = "legacy_cgi-2.6.2-py3-none-any.whl", hash = "sha256:a7b83afb1baf6ebeb56522537c5943ef9813cf933f6715e88a803f7edbce0bff"}, {file = "legacy_cgi-2.6.2.tar.gz", hash = "sha256:9952471ceb304043b104c22d00b4f333cac27a6abe446d8a528fc437cf13c85f"}, @@ -1542,14 +1489,13 @@ files = [ [[package]] name = "litellm" -version = "1.61.1" +version = "1.61.6" description = "Library to easily interface with LLM API providers" optional = false python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8" -groups = ["main", "dev"] files = [ - {file = "litellm-1.61.1-py3-none-any.whl", hash = "sha256:3bb546209979831c0440580b8b2309a138a4ad74ddb68309c5b619916b215bf2"}, - {file = "litellm-1.61.1.tar.gz", hash = "sha256:2d02c702444703e7b9e5b960c80a2acda764314497053b0ca5d2ec47329d70a9"}, + {file = "litellm-1.61.6-py3-none-any.whl", hash = "sha256:eef4c4a84a2c93de4c6d5a05a785f9b0cc61f63bafb3b3dc83d977db649e1b13"}, + {file = "litellm-1.61.6.tar.gz", hash = "sha256:2c613823f86ce2aa7956e2458857ab6aa62258dc7da9816bfdac90735be270be"}, ] [package.dependencies] @@ -1575,7 +1521,6 @@ version = "0.3.5" description = "Python bindings for the llama.cpp library" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "llama_cpp_python-0.3.5.tar.gz", hash = "sha256:f5ce47499d53d3973e28ca5bdaf2dfe820163fa3fb67e3050f98e2e9b58d2cf6"}, ] @@ -1598,7 +1543,6 @@ version = "1.3.9" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "Mako-1.3.9-py3-none-any.whl", hash = "sha256:95920acccb578427a9aa38e37a186b1e43156c87260d7ba18ca63aa4c7cbd3a1"}, {file = "mako-1.3.9.tar.gz", hash = "sha256:b5d65ff3462870feec922dbccf38f6efb44e5714d7b593a656be86663d8600ac"}, @@ -1618,7 +1562,6 @@ version = "1.2.1" description = "Static memory-efficient and fast Trie-like structures for Python." optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "marisa_trie-1.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a2eb41d2f9114d8b7bd66772c237111e00d2bae2260824560eaa0a1e291ce9e8"}, {file = "marisa_trie-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9e956e6a46f604b17d570901e66f5214fb6f658c21e5e7665deace236793cef6"}, @@ -1710,7 +1653,6 @@ version = "3.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, @@ -1735,7 +1677,6 @@ version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, @@ -1806,7 +1747,6 @@ version = "0.1.2" description = "Markdown URL utilities" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, @@ -1818,7 +1758,6 @@ version = "1.3.0" description = "Python library for arbitrary-precision floating-point arithmetic" optional = false python-versions = "*" -groups = ["main"] files = [ {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, @@ -1836,7 +1775,6 @@ version = "6.1.0" description = "multidict implementation" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, @@ -1938,7 +1876,6 @@ version = "1.0.12" description = "Cython bindings for MurmurHash" optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "murmurhash-1.0.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3f492bbf6f879b6eaf9da4be7471f4b68a3e3ae525aac0f35c2ae27ec91265c"}, {file = "murmurhash-1.0.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3493e0c10a64fa72026af2ea2271d8b3511a438de3c6a771b7a57771611b9c08"}, @@ -1984,7 +1921,6 @@ version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" -groups = ["dev"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -1996,7 +1932,6 @@ version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, @@ -2042,7 +1977,6 @@ version = "0.4.7" description = "The official Python client for Ollama." optional = false python-versions = "<4.0,>=3.8" -groups = ["main"] files = [ {file = "ollama-0.4.7-py3-none-any.whl", hash = "sha256:85505663cca67a83707be5fb3aeff0ea72e67846cea5985529d8eca4366564a1"}, {file = "ollama-0.4.7.tar.gz", hash = "sha256:891dcbe54f55397d82d289c459de0ea897e103b86a3f1fad0fdb1895922a75ff"}, @@ -2058,7 +1992,6 @@ version = "1.17.0" description = "Open Neural Network Exchange" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "onnx-1.17.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:38b5df0eb22012198cdcee527cc5f917f09cce1f88a69248aaca22bd78a7f023"}, {file = "onnx-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d545335cb49d4d8c47cc803d3a805deb7ad5d9094dc67657d66e568610a36d7d"}, @@ -2101,7 +2034,6 @@ version = "1.20.1" description = "ONNX Runtime is a runtime accelerator for Machine Learning models" optional = false python-versions = "*" -groups = ["main"] files = [ {file = "onnxruntime-1.20.1-cp310-cp310-macosx_13_0_universal2.whl", hash = "sha256:e50ba5ff7fed4f7d9253a6baf801ca2883cc08491f9d32d78a80da57256a5439"}, {file = "onnxruntime-1.20.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b2908b50101a19e99c4d4e97ebb9905561daf61829403061c1adc1b588bc0de"}, @@ -2140,7 +2072,6 @@ version = "1.61.1" description = "The official Python library for the openai API" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "openai-1.61.1-py3-none-any.whl", hash = "sha256:72b0826240ce26026ac2cd17951691f046e5be82ad122d20a8e1b30ca18bd11e"}, {file = "openai-1.61.1.tar.gz", hash = "sha256:ce1851507218209961f89f3520e06726c0aa7d0512386f0f977e3ac3e4f2472e"}, @@ -2166,7 +2097,6 @@ version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -2178,7 +2108,6 @@ version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, @@ -2190,7 +2119,6 @@ version = "6.1.1" description = "Python Build Reasonableness" optional = false python-versions = ">=2.6" -groups = ["dev"] files = [ {file = "pbr-6.1.1-py2.py3-none-any.whl", hash = "sha256:38d4daea5d9fa63b3f626131b9d34947fd0c8be9b05a29276870580050a25a76"}, {file = "pbr-6.1.1.tar.gz", hash = "sha256:93ea72ce6989eb2eed99d0f75721474f69ad88128afdef5ac377eb797c4bf76b"}, @@ -2205,7 +2133,6 @@ version = "8.13.54" description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers." optional = false python-versions = "*" -groups = ["main"] files = [ {file = "phonenumbers-8.13.54-py2.py3-none-any.whl", hash = "sha256:97624ada7260daafd09538baa6574b14cb9151cf29c5b22d9278abd050957edf"}, {file = "phonenumbers-8.13.54.tar.gz", hash = "sha256:4c32e3c941b24e5ce28d2211f624f0fef08462781e3d7e5e85192275cfd6c680"}, @@ -2217,7 +2144,6 @@ version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, @@ -2234,7 +2160,6 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -2250,7 +2175,6 @@ version = "3.0.9" description = "Cython hash table that trusts the keys are pre-hashed" optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "preshed-3.0.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f96ef4caf9847b2bb9868574dcbe2496f974e41c2b83d6621c24fb4c3fc57e3"}, {file = "preshed-3.0.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a61302cf8bd30568631adcdaf9e6b21d40491bd89ba8ebf67324f98b6c2a2c05"}, @@ -2297,7 +2221,6 @@ version = "2.2.357" description = "Presidio Analyzer package" optional = false python-versions = "<4.0,>=3.9" -groups = ["main"] files = [ {file = "presidio_analyzer-2.2.357-py3-none-any.whl", hash = "sha256:e7c545dcedb46c497ebd572578804ef7785c0628b85419c25ab947be05430483"}, ] @@ -2322,7 +2245,6 @@ version = "2.2.357" description = "Presidio Anonymizer package - replaces analyzed text with desired values." optional = false python-versions = "<4.0,>=3.9" -groups = ["main"] files = [ {file = "presidio_anonymizer-2.2.357-py3-none-any.whl", hash = "sha256:0b3e5e0526f5950bb9b27941e5b1b01b6761295d178a8ba4cedd2771aa2aee52"}, ] @@ -2340,7 +2262,6 @@ version = "0.2.1" description = "Accelerated property cache" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"}, {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"}, @@ -2432,7 +2353,6 @@ version = "5.29.3" description = "" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "protobuf-5.29.3-cp310-abi3-win32.whl", hash = "sha256:3ea51771449e1035f26069c4c7fd51fba990d07bc55ba80701c78f886bf9c888"}, {file = "protobuf-5.29.3-cp310-abi3-win_amd64.whl", hash = "sha256:a4fa6f80816a9a0678429e84973f2f98cbc218cca434abe8db2ad0bffc98503a"}, @@ -2453,8 +2373,6 @@ version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" -groups = ["main"] -markers = "platform_python_implementation != \"PyPy\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -2466,7 +2384,6 @@ version = "3.21.0" description = "Cryptographic library for Python" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -groups = ["main"] files = [ {file = "pycryptodome-3.21.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:dad9bf36eda068e89059d1f07408e397856be9511d7113ea4b586642a429a4fd"}, {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:a1752eca64c60852f38bb29e2c86fca30d7672c024128ef5d70cc15868fa10f4"}, @@ -2508,7 +2425,6 @@ version = "2.10.6" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"}, {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"}, @@ -2529,7 +2445,6 @@ version = "2.27.2" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, @@ -2642,7 +2557,6 @@ version = "2.7.1" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "pydantic_settings-2.7.1-py3-none-any.whl", hash = "sha256:590be9e6e24d06db33a4262829edef682500ef008565a969c73d39d5f8bfb3fd"}, {file = "pydantic_settings-2.7.1.tar.gz", hash = "sha256:10c9caad35e64bfb3c2fbf70a078c0e25cc92499782e5200747f942a065dec93"}, @@ -2663,7 +2577,6 @@ version = "2.19.1" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, @@ -2678,7 +2591,6 @@ version = "1.2.0" description = "Wrappers to call pyproject.toml-based build backend hooks." optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"}, {file = "pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8"}, @@ -2690,8 +2602,6 @@ version = "3.5.4" description = "A python implementation of GNU readline." optional = false python-versions = ">=3.8" -groups = ["main"] -markers = "sys_platform == \"win32\"" files = [ {file = "pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"}, {file = "pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7"}, @@ -2706,7 +2616,6 @@ version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, @@ -2727,7 +2636,6 @@ version = "0.25.3" description = "Pytest support for asyncio" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pytest_asyncio-0.25.3-py3-none-any.whl", hash = "sha256:9e89518e0f9bd08928f97a3482fdc4e244df17529460bc038291ccaf8f85c7c3"}, {file = "pytest_asyncio-0.25.3.tar.gz", hash = "sha256:fc1da2cf9f125ada7e710b4ddad05518d4cee187ae9412e9ac9271003497f07a"}, @@ -2746,7 +2654,6 @@ version = "6.0.0" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"}, {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"}, @@ -2765,7 +2672,6 @@ version = "1.0.1" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, @@ -2780,7 +2686,6 @@ version = "6.0.2" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, @@ -2843,7 +2748,6 @@ version = "0.36.2" description = "JSON Referencing + Python" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"}, {file = "referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa"}, @@ -2860,7 +2764,6 @@ version = "2024.11.6" description = "Alternative regular expression module, to replace re." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"}, {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"}, @@ -2964,7 +2867,6 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -2986,7 +2888,6 @@ version = "2.1.0" description = "File transport adapter for Requests" optional = false python-versions = "*" -groups = ["main"] files = [ {file = "requests_file-2.1.0-py2.py3-none-any.whl", hash = "sha256:cf270de5a4c5874e84599fc5778303d496c10ae5e870bfa378818f35d21bda5c"}, {file = "requests_file-2.1.0.tar.gz", hash = "sha256:0f549a3f3b0699415ac04d167e9cb39bccfb730cb832b4d20be3d9867356e658"}, @@ -3001,7 +2902,6 @@ version = "13.9.4" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.8.0" -groups = ["dev"] files = [ {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, @@ -3020,7 +2920,6 @@ version = "0.22.3" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "rpds_py-0.22.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967"}, {file = "rpds_py-0.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37"}, @@ -3133,7 +3032,6 @@ version = "0.9.6" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "ruff-0.9.6-py3-none-linux_armv6l.whl", hash = "sha256:2f218f356dd2d995839f1941322ff021c72a492c470f0b26a34f844c29cdf5ba"}, {file = "ruff-0.9.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b908ff4df65dad7b251c9968a2e4560836d8f5487c2f0cc238321ed951ea0504"}, @@ -3161,7 +3059,6 @@ version = "1.6.1" description = "A set of python modules for machine learning and data mining" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "scikit_learn-1.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d056391530ccd1e501056160e3c9673b4da4805eb67eb2bdf4e983e1f9c9204e"}, {file = "scikit_learn-1.6.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0c8d036eb937dbb568c6242fa598d551d88fb4399c0344d95c001980ec1c7d36"}, @@ -3216,7 +3113,6 @@ version = "1.15.1" description = "Fundamental algorithms for scientific computing in Python" optional = false python-versions = ">=3.10" -groups = ["dev"] files = [ {file = "scipy-1.15.1-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:c64ded12dcab08afff9e805a67ff4480f5e69993310e093434b10e85dc9d43e1"}, {file = "scipy-1.15.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:5b190b935e7db569960b48840e5bef71dc513314cc4e79a1b7d14664f57fd4ff"}, @@ -3274,7 +3170,6 @@ version = "75.8.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3"}, {file = "setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6"}, @@ -3295,7 +3190,6 @@ version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -3307,7 +3201,6 @@ version = "6.4.0" description = "Utils for streaming large files (S3, HDFS, GCS, Azure Blob Storage, gzip, bz2...)" optional = false python-versions = ">=3.6,<4.0" -groups = ["main"] files = [ {file = "smart_open-6.4.0-py3-none-any.whl", hash = "sha256:8d3ef7e6997e8e42dd55c74166ed21e6ac70664caa32dd940b26d54a8f6b4142"}, {file = "smart_open-6.4.0.tar.gz", hash = "sha256:be3c92c246fbe80ebce8fbacb180494a481a77fcdcb7c1aadb2ea5b9c2bee8b9"}, @@ -3329,7 +3222,6 @@ version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -3341,7 +3233,6 @@ version = "3.7.5" description = "Industrial-strength Natural Language Processing (NLP) in Python" optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "spacy-3.7.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8002897701429ee2ab5ff6921ae43560f4cd17184cb1e10dad761901c12dcb85"}, {file = "spacy-3.7.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:43acd19efc845e9126b61a05ed7508a0aff509e96e15563f30f810c19e636b7c"}, @@ -3429,7 +3320,6 @@ version = "3.0.12" description = "Legacy registered functions for spaCy backwards compatibility" optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "spacy-legacy-3.0.12.tar.gz", hash = "sha256:b37d6e0c9b6e1d7ca1cf5bc7152ab64a4c4671f59c85adaf7a3fcb870357a774"}, {file = "spacy_legacy-3.0.12-py2.py3-none-any.whl", hash = "sha256:476e3bd0d05f8c339ed60f40986c07387c0a71479245d6d0f4298dbd52cda55f"}, @@ -3441,7 +3331,6 @@ version = "1.0.5" description = "Logging utilities for SpaCy" optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "spacy-loggers-1.0.5.tar.gz", hash = "sha256:d60b0bdbf915a60e516cc2e653baeff946f0cfc461b452d11a4d5458c6fe5f24"}, {file = "spacy_loggers-1.0.5-py3-none-any.whl", hash = "sha256:196284c9c446cc0cdb944005384270d775fdeaf4f494d8e269466cfa497ef645"}, @@ -3453,7 +3342,6 @@ version = "2.0.38" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "SQLAlchemy-2.0.38-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5e1d9e429028ce04f187a9f522818386c8b076723cdbe9345708384f49ebcec6"}, {file = "SQLAlchemy-2.0.38-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b87a90f14c68c925817423b0424381f0e16d80fc9a1a1046ef202ab25b19a444"}, @@ -3549,7 +3437,6 @@ version = "0.0.4" description = "" optional = false python-versions = "*" -groups = ["main"] files = [ {file = "sqlite_vec_sl_tmp-0.0.4-py3-none-macosx_10_6_x86_64.whl", hash = "sha256:5ff08375a51d9d8284b4e14a6a2ccb8faabc5fe8e82953b8a8861302ef2ab147"}, {file = "sqlite_vec_sl_tmp-0.0.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:0a8ad2980e95067560670c24afc6a6ba43227387f8c38e833ae8c7d9382080f2"}, @@ -3564,7 +3451,6 @@ version = "2.5.1" description = "Modern high-performance serialization utilities for Python" optional = false python-versions = "<3.14,>=3.9" -groups = ["main"] files = [ {file = "srsly-2.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d0cda6f65cc0dd1daf47e856b0d6c5d51db8a9343c5007723ca06903dcfe367d"}, {file = "srsly-2.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf643e6f45c266cfacea54997a1f9cfe0113fadac1ac21a1ec5b200cfe477ba0"}, @@ -3613,7 +3499,6 @@ version = "0.45.3" description = "The little ASGI library that shines." optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "starlette-0.45.3-py3-none-any.whl", hash = "sha256:dfb6d332576f136ec740296c7e8bb8c8a7125044e7c6da30744718880cdd059d"}, {file = "starlette-0.45.3.tar.gz", hash = "sha256:2cbcba2a75806f8a41c722141486f37c28e30a0921c5f6fe4346cb0dcee1302f"}, @@ -3631,7 +3516,6 @@ version = "5.4.0" description = "Manage dynamic plugins for Python applications" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "stevedore-5.4.0-py3-none-any.whl", hash = "sha256:b0be3c4748b3ea7b854b265dcb4caa891015e442416422be16f8b31756107857"}, {file = "stevedore-5.4.0.tar.gz", hash = "sha256:79e92235ecb828fe952b6b8b0c6c87863248631922c8e8e0fa5b17b232c4514d"}, @@ -3646,7 +3530,6 @@ version = "25.1.0" description = "Structured Logging for Python" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "structlog-25.1.0-py3-none-any.whl", hash = "sha256:843fe4f254540329f380812cbe612e1af5ec5b8172205ae634679cd35a6d6321"}, {file = "structlog-25.1.0.tar.gz", hash = "sha256:2ef2a572e0e27f09664965d31a576afe64e46ac6084ef5cec3c2b8cd6e4e3ad3"}, @@ -3664,7 +3547,6 @@ version = "1.13.3" description = "Computer algebra system (CAS) in Python" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "sympy-1.13.3-py3-none-any.whl", hash = "sha256:54612cf55a62755ee71824ce692986f23c88ffa77207b30c1368eda4a7060f73"}, {file = "sympy-1.13.3.tar.gz", hash = "sha256:b27fd2c6530e0ab39e275fc9b683895367e51d5da91baa8d3d64db2565fec4d9"}, @@ -3682,7 +3564,6 @@ version = "8.2.5" description = "A refreshing functional take on deep learning, compatible with your favorite libraries" optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "thinc-8.2.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dc267f6aad80a681a85f50383afe91da9e2bec56fefdda86bfa2e4f529bef191"}, {file = "thinc-8.2.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d80f1e497971c9fa0938f5cc8fe607bbe87356b405fb7bbc3ff9f32fb4eed3bb"}, @@ -3752,7 +3633,6 @@ version = "3.5.0" description = "threadpoolctl" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "threadpoolctl-3.5.0-py3-none-any.whl", hash = "sha256:56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467"}, {file = "threadpoolctl-3.5.0.tar.gz", hash = "sha256:082433502dd922bf738de0d8bcc4fdcbf0979ff44c42bd40f5af8a282f6fa107"}, @@ -3764,7 +3644,6 @@ version = "0.8.0" description = "tiktoken is a fast BPE tokeniser for use with OpenAI's models" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "tiktoken-0.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b07e33283463089c81ef1467180e3e00ab00d46c2c4bbcef0acab5f771d6695e"}, {file = "tiktoken-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9269348cb650726f44dd3bbb3f9110ac19a8dcc8f54949ad3ef652ca22a38e21"}, @@ -3812,7 +3691,6 @@ version = "5.1.3" description = "Accurately separates a URL's subdomain, domain, and public suffix, using the Public Suffix List (PSL). By default, this includes the public ICANN TLDs and their exceptions. You can optionally support the Public Suffix List's private domains as well." optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "tldextract-5.1.3-py3-none-any.whl", hash = "sha256:78de310cc2ca018692de5ddf320f9d6bd7c5cf857d0fd4f2175f0cdf4440ea75"}, {file = "tldextract-5.1.3.tar.gz", hash = "sha256:d43c7284c23f5dc8a42fd0fee2abede2ff74cc622674e4cb07f514ab3330c338"}, @@ -3834,7 +3712,6 @@ version = "0.21.0" description = "" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "tokenizers-0.21.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3c4c93eae637e7d2aaae3d376f06085164e1660f89304c0ab2b1d08a406636b2"}, {file = "tokenizers-0.21.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:f53ea537c925422a2e0e92a24cce96f6bc5046bbef24a1652a5edc8ba975f62e"}, @@ -3867,7 +3744,6 @@ version = "4.67.1" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, @@ -3889,7 +3765,6 @@ version = "0.24.0" description = "Python bindings to the Tree-sitter parsing library" optional = false python-versions = ">=3.10" -groups = ["main"] files = [ {file = "tree-sitter-0.24.0.tar.gz", hash = "sha256:abd95af65ca2f4f7eca356343391ed669e764f37748b5352946f00f7fc78e734"}, {file = "tree_sitter-0.24.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f3f00feff1fc47a8e4863561b8da8f5e023d382dd31ed3e43cd11d4cae445445"}, @@ -3932,7 +3807,6 @@ version = "0.23.4" description = "Go grammar for tree-sitter" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "tree_sitter_go-0.23.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c9320f87a05cd47fa0f627b9329bbc09b7ed90de8fe4f5882aed318d6e19962d"}, {file = "tree_sitter_go-0.23.4-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:914e63d16b36ab0e4f52b031e574b82d17d0bbfecca138ae83e887a1cf5b71ac"}, @@ -3953,7 +3827,6 @@ version = "0.23.5" description = "Java grammar for tree-sitter" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "tree_sitter_java-0.23.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:355ce0308672d6f7013ec913dee4a0613666f4cda9044a7824240d17f38209df"}, {file = "tree_sitter_java-0.23.5-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:24acd59c4720dedad80d548fe4237e43ef2b7a4e94c8549b0ca6e4c4d7bf6e69"}, @@ -3974,7 +3847,6 @@ version = "0.23.1" description = "JavaScript grammar for tree-sitter" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "tree_sitter_javascript-0.23.1-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6ca583dad4bd79d3053c310b9f7208cd597fd85f9947e4ab2294658bb5c11e35"}, {file = "tree_sitter_javascript-0.23.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:94100e491a6a247aa4d14caf61230c171b6376c863039b6d9cd71255c2d815ec"}, @@ -3995,7 +3867,6 @@ version = "0.23.6" description = "Python grammar for tree-sitter" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "tree_sitter_python-0.23.6-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:28fbec8f74eeb2b30292d97715e60fac9ccf8a8091ce19b9d93e9b580ed280fb"}, {file = "tree_sitter_python-0.23.6-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:680b710051b144fedf61c95197db0094f2245e82551bf7f0c501356333571f7a"}, @@ -4016,7 +3887,6 @@ version = "0.23.2" description = "Rust grammar for tree-sitter" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "tree_sitter_rust-0.23.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b6b26a4c07ddc243f3701450ff34093b8e3b08f14d269db2d049c625d151677c"}, {file = "tree_sitter_rust-0.23.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:c6224f608df559d75425e5ef428f635b9fb87d7aa8716444915ee67ec6955085"}, @@ -4037,7 +3907,6 @@ version = "0.9.4" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "typer-0.9.4-py3-none-any.whl", hash = "sha256:aa6c4a4e2329d868b80ecbaf16f807f2b54e192209d7ac9dd42691d63f7a54eb"}, {file = "typer-0.9.4.tar.gz", hash = "sha256:f714c2d90afae3a7929fcd72a3abb08df305e1ff61719381384211c4070af57f"}, @@ -4059,7 +3928,6 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -4071,7 +3939,6 @@ version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, @@ -4089,7 +3956,6 @@ version = "0.34.0" description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"}, {file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"}, @@ -4108,7 +3974,6 @@ version = "1.1.3" description = "A lightweight console printing and formatting toolkit" optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "wasabi-1.1.3-py3-none-any.whl", hash = "sha256:f76e16e8f7e79f8c4c8be49b4024ac725713ab10cd7f19350ad18a8e3f71728c"}, {file = "wasabi-1.1.3.tar.gz", hash = "sha256:4bb3008f003809db0c3e28b4daf20906ea871a2bb43f9914197d540f4f2e0878"}, @@ -4123,7 +3988,6 @@ version = "0.4.1" description = "Weasel: A small and easy workflow system" optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "weasel-0.4.1-py3-none-any.whl", hash = "sha256:24140a090ea1ac512a2b2f479cc64192fd1d527a7f3627671268d08ed5ac418c"}, {file = "weasel-0.4.1.tar.gz", hash = "sha256:aabc210f072e13f6744e5c3a28037f93702433405cd35673f7c6279147085aa9"}, @@ -4146,7 +4010,6 @@ version = "0.45.1" description = "A built-package format for Python" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248"}, {file = "wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729"}, @@ -4161,7 +4024,6 @@ version = "1.18.3" description = "Yet another URL library" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, @@ -4258,7 +4120,6 @@ version = "3.21.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, @@ -4273,6 +4134,6 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", type = ["pytest-mypy"] [metadata] -lock-version = "2.1" +lock-version = "2.0" python-versions = ">=3.12,<3.13" -content-hash = "30b32705ef9547e3870408ca12a813e5d9fff080a372faf3a00e4ba9a9d51606" +content-hash = "04bcc29c963b6241e75fe9bb5337471401819c4119ddbedee8b72e2f070a7cb8" diff --git a/pyproject.toml b/pyproject.toml index 162c3d54..ba19e2fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ PyYAML = "==6.0.2" fastapi = "==0.115.8" uvicorn = "==0.34.0" structlog = "==25.1.0" -litellm = "==1.61.1" +litellm = "==1.61.6" llama_cpp_python = "==0.3.5" cryptography = "==44.0.1" sqlalchemy = "==2.0.38" @@ -46,10 +46,10 @@ pytest = "==8.3.4" pytest-cov = "==6.0.0" black = "==25.1.0" ruff = "==0.9.6" -bandit = "==1.8.2" +bandit = "==1.8.3" build = "==1.2.2.post1" wheel = "==0.45.1" -litellm = "==1.61.1" +litellm = "==1.61.6" pytest-asyncio = "==0.25.3" llama_cpp_python = "==0.3.5" scikit-learn = "==1.6.1" diff --git a/scripts/import_packages.py b/scripts/import_packages.py index e96d65e1..9d9241b3 100644 --- a/scripts/import_packages.py +++ b/scripts/import_packages.py @@ -7,6 +7,7 @@ import numpy as np import sqlite_vec_sl_tmp +from codegate.config import Config from codegate.inference.inference_engine import LlamaCppInferenceEngine from codegate.utils.utils import generate_vector_string @@ -55,7 +56,9 @@ def setup_schema(self): async def process_package(self, package): vector_str = generate_vector_string(package) - vector = await self.inference_engine.embed(self.model_path, [vector_str]) + vector = await self.inference_engine.embed( + self.model_path, [vector_str], n_gpu_layers=Config.get_config().chat_model_n_gpu_layers + ) vector_array = np.array(vector[0], dtype=np.float32) cursor = self.conn.cursor() diff --git a/src/codegate/api/v1.py b/src/codegate/api/v1.py index 3b837a8b..c5ac57d5 100644 --- a/src/codegate/api/v1.py +++ b/src/codegate/api/v1.py @@ -414,7 +414,9 @@ async def get_workspace_messages(workspace_name: str) -> List[v1_models.Conversa try: prompts_with_output_alerts_usage = ( - await dbreader.get_prompts_with_output_alerts_usage_by_workspace_id(ws.id) + await dbreader.get_prompts_with_output_alerts_usage_by_workspace_id( + ws.id, AlertSeverity.CRITICAL.value + ) ) conversations, _ = await v1_processing.parse_messages_in_conversations( prompts_with_output_alerts_usage diff --git a/src/codegate/api/v1_processing.py b/src/codegate/api/v1_processing.py index fc902d59..0dbce577 100644 --- a/src/codegate/api/v1_processing.py +++ b/src/codegate/api/v1_processing.py @@ -534,4 +534,4 @@ async def remove_duplicate_alerts(alerts: List[v1_models.Alert]) -> List[v1_mode seen[key] = alert unique_alerts.append(alert) - return list(seen.values()) + return unique_alerts diff --git a/src/codegate/db/connection.py b/src/codegate/db/connection.py index f14c0bc8..9c9abd79 100644 --- a/src/codegate/db/connection.py +++ b/src/codegate/db/connection.py @@ -586,7 +586,7 @@ async def get_prompts_with_output(self, workpace_id: str) -> List[GetPromptWithO return prompts async def get_prompts_with_output_alerts_usage_by_workspace_id( - self, workspace_id: str + self, workspace_id: str, trigger_category: Optional[str] = None ) -> List[GetPromptWithOutputsRow]: """ Get all prompts with their outputs, alerts and token usage by workspace_id. @@ -602,12 +602,17 @@ async def get_prompts_with_output_alerts_usage_by_workspace_id( LEFT JOIN outputs o ON p.id = o.prompt_id LEFT JOIN alerts a ON p.id = a.prompt_id WHERE p.workspace_id = :workspace_id + AND a.trigger_category LIKE :trigger_category ORDER BY o.timestamp DESC, a.timestamp DESC """ # noqa: E501 ) - conditions = {"workspace_id": workspace_id} - rows = await self._exec_select_conditions_to_pydantic( - IntermediatePromptWithOutputUsageAlerts, sql, conditions, should_raise=True + # If trigger category is None we want to get all alerts + trigger_category = trigger_category if trigger_category else "%" + conditions = {"workspace_id": workspace_id, "trigger_category": trigger_category} + rows: List[IntermediatePromptWithOutputUsageAlerts] = ( + await self._exec_select_conditions_to_pydantic( + IntermediatePromptWithOutputUsageAlerts, sql, conditions, should_raise=True + ) ) prompts_dict: Dict[str, GetPromptWithOutputsRow] = {} diff --git a/src/codegate/inference/inference_engine.py b/src/codegate/inference/inference_engine.py index 9433a345..6e0a6e50 100644 --- a/src/codegate/inference/inference_engine.py +++ b/src/codegate/inference/inference_engine.py @@ -1,5 +1,13 @@ +from typing import Iterator, List, Union + import structlog -from llama_cpp import Llama +from llama_cpp import ( + CreateChatCompletionResponse, + CreateChatCompletionStreamResponse, + CreateCompletionResponse, + CreateCompletionStreamResponse, + Llama, +) logger = structlog.get_logger("codegate") @@ -35,7 +43,9 @@ def _close_models(self): model._sampler.close() model.close() - async def __get_model(self, model_path, embedding=False, n_ctx=512, n_gpu_layers=0) -> Llama: + async def __get_model( + self, model_path: str, embedding: bool = False, n_ctx: int = 512, n_gpu_layers: int = 0 + ) -> Llama: """ Returns Llama model object from __models if present. Otherwise, the model is loaded and added to __models and returned. @@ -55,7 +65,9 @@ async def __get_model(self, model_path, embedding=False, n_ctx=512, n_gpu_layers return self.__models[model_path] - async def complete(self, model_path, n_ctx=512, n_gpu_layers=0, **completion_request): + async def complete( + self, model_path: str, n_ctx: int = 512, n_gpu_layers: int = 0, **completion_request + ) -> Union[CreateCompletionResponse, Iterator[CreateCompletionStreamResponse]]: """ Generates a chat completion using the specified model and request parameters. """ @@ -64,7 +76,9 @@ async def complete(self, model_path, n_ctx=512, n_gpu_layers=0, **completion_req ) return model.create_completion(**completion_request) - async def chat(self, model_path, n_ctx=512, n_gpu_layers=0, **chat_completion_request): + async def chat( + self, model_path: str, n_ctx: int = 512, n_gpu_layers: int = 0, **chat_completion_request + ) -> Union[CreateChatCompletionResponse, Iterator[CreateChatCompletionStreamResponse]]: """ Generates a chat completion using the specified model and request parameters. """ @@ -73,18 +87,20 @@ async def chat(self, model_path, n_ctx=512, n_gpu_layers=0, **chat_completion_re ) return model.create_chat_completion(**chat_completion_request) - async def embed(self, model_path, content): + async def embed(self, model_path: str, content: List[str], n_gpu_layers=0) -> List[List[float]]: """ Generates an embedding for the given content using the specified model. """ logger.debug( "Generating embedding", model=model_path.split("/")[-1], - content=content, + content=content[0][0 : min(100, len(content[0]))], content_length=len(content[0]) if content else 0, ) - model = await self.__get_model(model_path=model_path, embedding=True) + model = await self.__get_model( + model_path=model_path, embedding=True, n_gpu_layers=n_gpu_layers + ) embedding = model.embed(content) logger.debug( diff --git a/src/codegate/pipeline/comment/output.py b/src/codegate/pipeline/comment/output.py index ce70138a..44a2f1af 100644 --- a/src/codegate/pipeline/comment/output.py +++ b/src/codegate/pipeline/comment/output.py @@ -12,7 +12,8 @@ ) from codegate.pipeline.base import PipelineContext from codegate.pipeline.output import OutputPipelineContext, OutputPipelineStep -from codegate.pipeline.suspicious_commands.suspicious_commands import SuspiciousCommands + +# from codegate.pipeline.suspicious_commands.suspicious_commands import check_suspicious_code from codegate.storage import StorageEngine from codegate.utils.package_extractor import PackageExtractor @@ -51,24 +52,11 @@ def _create_chunk(self, original_chunk: ModelResponse, content: str) -> ModelRes async def _snippet_comment(self, snippet: CodeSnippet, context: PipelineContext) -> str: """Create a comment for a snippet""" comment = "" - sc = SuspiciousCommands.get_instance() - class_, prob = await sc.classify_phrase(snippet.code) - if class_ == 1: - liklihood = "possibly" - language = "code" - if prob > 0.9: - liklihood = "likely" - if snippet.language is not None: - language = snippet.language - if language not in [ - "python", - "javascript", - "typescript", - "go", - "rust", - "java", - ]: # noqa: E501 - comment = f"{comment}\n\nš”ļø CodeGate: The {language} supplied is {liklihood} unsafe. Please check carefully!\n\n" # noqa: E501 + + # Remove this for now. We need to find a better place for it. + # comment, is_suspicious = await check_suspicious_code(snippet.code, snippet.language) + # if is_suspicious: + # comment += comment snippet.libraries = PackageExtractor.extract_packages(snippet.code, snippet.language) diff --git a/src/codegate/pipeline/pii/analyzer.py b/src/codegate/pipeline/pii/analyzer.py index be854aae..a1ed5bed 100644 --- a/src/codegate/pipeline/pii/analyzer.py +++ b/src/codegate/pipeline/pii/analyzer.py @@ -100,7 +100,7 @@ def __init__(self): PiiAnalyzer._instance = self def analyze( - self, text: str, context: Optional["PipelineContext"] = None + self, text: str, context: Optional[PipelineContext] = None ) -> Tuple[str, List[Dict[str, Any]], PiiSessionStore]: # Prioritize credit card detection first entities = [ diff --git a/src/codegate/pipeline/pii/manager.py b/src/codegate/pipeline/pii/manager.py index e4ac69ab..54112713 100644 --- a/src/codegate/pipeline/pii/manager.py +++ b/src/codegate/pipeline/pii/manager.py @@ -1,7 +1,8 @@ -from typing import Any, Dict, List, Tuple +from typing import Any, Dict, List, Optional, Tuple import structlog +from codegate.pipeline.base import PipelineContext from codegate.pipeline.pii.analyzer import PiiAnalyzer, PiiSessionStore logger = structlog.get_logger("codegate") @@ -52,9 +53,11 @@ def session_store(self) -> PiiSessionStore: # Always return the analyzer's current session store return self.analyzer.session_store - def analyze(self, text: str) -> Tuple[str, List[Dict[str, Any]]]: + def analyze( + self, text: str, context: Optional[PipelineContext] = None + ) -> Tuple[str, List[Dict[str, Any]]]: # Call analyzer and get results - anonymized_text, found_pii, _ = self.analyzer.analyze(text) + anonymized_text, found_pii, _ = self.analyzer.analyze(text, context=context) # Log found PII details (without modifying the found_pii list) if found_pii: diff --git a/src/codegate/pipeline/pii/pii.py b/src/codegate/pipeline/pii/pii.py index d4581cd9..36b3e1a1 100644 --- a/src/codegate/pipeline/pii/pii.py +++ b/src/codegate/pipeline/pii/pii.py @@ -80,7 +80,7 @@ async def process( if "content" in message and message["content"]: # This is where analyze and anonymize the text original_text = str(message["content"]) - anonymized_text, pii_details = self.pii_manager.analyze(original_text) + anonymized_text, pii_details = self.pii_manager.analyze(original_text, context) if pii_details: total_pii_found += len(pii_details) diff --git a/src/codegate/pipeline/suspicious_commands/suspicious_commands.py b/src/codegate/pipeline/suspicious_commands/suspicious_commands.py index 7c61454a..ca3c3e8e 100644 --- a/src/codegate/pipeline/suspicious_commands/suspicious_commands.py +++ b/src/codegate/pipeline/suspicious_commands/suspicious_commands.py @@ -80,7 +80,9 @@ async def compute_embeddings(self, phrases): Returns: torch.Tensor: Tensor of embeddings. """ - embeddings = await self.inference_engine.embed(self.model_path, phrases) + embeddings = await self.inference_engine.embed( + self.model_path, phrases, n_gpu_layers=Config.get_config().chat_model_n_gpu_layers + ) return embeddings async def classify_phrase(self, phrase, embeddings=None): @@ -108,3 +110,35 @@ async def classify_phrase(self, phrase, embeddings=None): prediction = np.argmax(ort_outs[0]) probability = np.max(ort_outs[0]) return prediction, probability + + +async def check_suspicious_code(code, language=None): + """ + Check if the given code is suspicious and return a comment if it is. + + Args: + code (str): The code to check. + language (str, optional): The language of the code. + + Returns: + tuple: A comment string and a boolean indicating if the code is suspicious. + """ + sc = SuspiciousCommands.get_instance() + comment = "" + class_, prob = await sc.classify_phrase(code) + if class_ == 1: + liklihood = "possibly" + if prob > 0.9: + liklihood = "likely" + if language is None: + language = "code" + if language not in [ + "python", + "javascript", + "typescript", + "go", + "rust", + "java", + ]: + comment = f"{comment}\n\nš”ļø CodeGate: The {language} supplied is {liklihood} unsafe. Please check carefully!\n\n" # noqa: E501 + return comment, class_ == 1 diff --git a/src/codegate/pipeline/suspicious_commands/suspicious_commands_trainer.py b/src/codegate/pipeline/suspicious_commands/suspicious_commands_trainer.py index d31e981d..5b8c71f0 100644 --- a/src/codegate/pipeline/suspicious_commands/suspicious_commands_trainer.py +++ b/src/codegate/pipeline/suspicious_commands/suspicious_commands_trainer.py @@ -107,7 +107,9 @@ async def train(self, phrases, labels): phrases (list of str): List of phrases to train on. labels (list of int): Corresponding labels for the phrases. """ - embeds = await self.inference_engine.embed(self.model_path, phrases) + embeds = await self.inference_engine.embed( + self.model_path, phrases, n_gpu_layers=Config.get_config().chat_model_n_gpu_layers + ) if isinstance(embeds[0], list): embedding_dim = len(embeds[0]) else: diff --git a/src/codegate/providers/base.py b/src/codegate/providers/base.py index 3edced69..d22afcc0 100644 --- a/src/codegate/providers/base.py +++ b/src/codegate/providers/base.py @@ -133,12 +133,23 @@ async def _run_output_stream_pipeline( denormalized_stream = self._output_normalizer.denormalize_streaming(pipeline_output_stream) return denormalized_stream - def _run_output_pipeline( + async def _run_output_pipeline( self, - normalized_response: ModelResponse, + input_context: PipelineContext, + model_response: Any, ) -> ModelResponse: - # we don't have a pipeline for non-streamed output yet - return normalized_response + """ + Run the output pipeline for a single response. + + For the moment we don't have a pipeline for non-streamed output, so we + just normalize the response and record the context. It is done here to match + the behaviour of the streaming pipeline. + """ + normalized_response = self._output_normalizer.normalize(model_response) + input_context.add_output(normalized_response) + await self._db_recorder.record_context(input_context) + output_result = self._output_normalizer.denormalize(normalized_response) + return output_result async def _run_input_pipeline( self, @@ -263,10 +274,7 @@ async def complete( is_fim_request=is_fim_request, ) if not streaming: - normalized_response = self._output_normalizer.normalize(model_response) - pipeline_output = self._run_output_pipeline(normalized_response) - await self._db_recorder.record_context(input_pipeline_result.context) - return self._output_normalizer.denormalize(pipeline_output) + return await self._run_output_pipeline(input_pipeline_result.context, model_response) pipeline_output_stream = await self._run_output_stream_pipeline( input_pipeline_result.context, model_response, is_fim_request=is_fim_request # type: ignore diff --git a/src/codegate/providers/copilot/provider.py b/src/codegate/providers/copilot/provider.py index 35b26ae4..bf711210 100644 --- a/src/codegate/providers/copilot/provider.py +++ b/src/codegate/providers/copilot/provider.py @@ -111,19 +111,29 @@ class HttpResponse: headers: List[str] body: Optional[bytes] = None - def reconstruct(self) -> bytes: - """Reconstruct HTTP response from stored details""" + def reconstruct_headers(self) -> bytes: + """ + Reconstruct the HTTP header of the response. + """ headers = "\r\n".join(self.headers) status_line = f"{self.version} {self.status_code} {self.reason}\r\n" header_block = f"{status_line}{headers}\r\n\r\n" + return header_block.encode("utf-8") - # Convert header block to bytes and combine with body - result = header_block.encode("utf-8") + def reconstruct_body(self) -> bytes: + """ + Reconstruct the body of the response. + """ + result = b"" if self.body: result += self.body - + result += b"\n\n" return result + def reconstruct(self) -> bytes: + """Reconstruct HTTP response from stored details""" + return self.reconstruct_headers() + self.reconstruct_body() + def extract_path(full_path: str) -> str: """Extract clean path from full URL or path string""" @@ -387,8 +397,12 @@ async def _forward_data_to_target(self, data: bytes) -> None: # request to the target self.target_transport.close() - # Send the shortcut response data in a chunk - chunk = pipeline_output.reconstruct() + # Send the HTTP headers + # Note that this representation ends with \r\n\r\n + self.transport.write(pipeline_output.reconstruct_headers()) + + # Encode the body, send its length, then the data + chunk = pipeline_output.reconstruct_body() chunk_size = hex(len(chunk))[2:] + "\r\n" self.transport.write(chunk_size.encode()) self.transport.write(chunk) diff --git a/src/codegate/storage/storage_engine.py b/src/codegate/storage/storage_engine.py index 9543fe70..f02cf72b 100644 --- a/src/codegate/storage/storage_engine.py +++ b/src/codegate/storage/storage_engine.py @@ -185,7 +185,11 @@ async def search( elif query: # Generate embedding for the query - query_vector = await self.inference_engine.embed(self.model_path, [query]) + query_vector = await self.inference_engine.embed( + self.model_path, + [query], + n_gpu_layers=Config.get_config().chat_model_n_gpu_layers, + ) query_embedding = np.array(query_vector[0], dtype=np.float32) query_embedding_bytes = query_embedding.tobytes() diff --git a/tests/api/__init__.py b/tests/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/api/test_v1_processing.py b/tests/api/test_v1_processing.py index 28d70fe1..ad8ffcbd 100644 --- a/tests/api/test_v1_processing.py +++ b/tests/api/test_v1_processing.py @@ -4,13 +4,14 @@ import pytest -from codegate.api.v1_models import PartialQuestions +from codegate.api import v1_models from codegate.api.v1_processing import ( _get_partial_question_answer, _group_partial_messages, _is_system_prompt, parse_output, parse_request, + remove_duplicate_alerts, ) from codegate.db.models import GetPromptWithOutputsRow @@ -193,14 +194,14 @@ async def test_get_question_answer(request_msg_list, output_msg_str, row): # 1) No subsets: all items stand alone ( [ - PartialQuestions( + v1_models.PartialQuestions( messages=["A"], timestamp=datetime.datetime(2023, 1, 1, 0, 0, 0), message_id="pq1", provider="providerA", type="chat", ), - PartialQuestions( + v1_models.PartialQuestions( messages=["B"], timestamp=datetime.datetime(2023, 1, 1, 0, 0, 1), message_id="pq2", @@ -214,14 +215,14 @@ async def test_get_question_answer(request_msg_list, output_msg_str, row): # - "Hello" is a subset of "Hello, how are you?" ( [ - PartialQuestions( + v1_models.PartialQuestions( messages=["Hello"], timestamp=datetime.datetime(2022, 1, 1, 0, 0, 0), message_id="pq1", provider="providerA", type="chat", ), - PartialQuestions( + v1_models.PartialQuestions( messages=["Hello", "How are you?"], timestamp=datetime.datetime(2022, 1, 1, 0, 0, 10), message_id="pq2", @@ -238,28 +239,28 @@ async def test_get_question_answer(request_msg_list, output_msg_str, row): # superset. ( [ - PartialQuestions( + v1_models.PartialQuestions( messages=["Hello"], timestamp=datetime.datetime(2023, 1, 1, 10, 0, 0), message_id="pq1", provider="providerA", type="chat", ), - PartialQuestions( + v1_models.PartialQuestions( messages=["Hello"], timestamp=datetime.datetime(2023, 1, 1, 11, 0, 0), message_id="pq2", provider="providerA", type="chat", ), - PartialQuestions( + v1_models.PartialQuestions( messages=["Hello"], timestamp=datetime.datetime(2023, 1, 1, 12, 0, 0), message_id="pq3", provider="providerA", type="chat", ), - PartialQuestions( + v1_models.PartialQuestions( messages=["Hello", "Bye"], timestamp=datetime.datetime(2023, 1, 1, 11, 0, 5), message_id="pq4", @@ -281,7 +282,7 @@ async def test_get_question_answer(request_msg_list, output_msg_str, row): ( [ # Superset - PartialQuestions( + v1_models.PartialQuestions( messages=["hi", "welcome", "bye"], timestamp=datetime.datetime(2023, 5, 1, 9, 0, 0), message_id="pqS1", @@ -289,21 +290,21 @@ async def test_get_question_answer(request_msg_list, output_msg_str, row): type="chat", ), # Subsets for pqS1 - PartialQuestions( + v1_models.PartialQuestions( messages=["hi", "welcome"], timestamp=datetime.datetime(2023, 5, 1, 9, 0, 5), message_id="pqA1", provider="providerB", type="chat", ), - PartialQuestions( + v1_models.PartialQuestions( messages=["hi", "bye"], timestamp=datetime.datetime(2023, 5, 1, 9, 0, 10), message_id="pqA2", provider="providerB", type="chat", ), - PartialQuestions( + v1_models.PartialQuestions( messages=["hi", "bye"], timestamp=datetime.datetime(2023, 5, 1, 9, 0, 12), message_id="pqA3", @@ -311,7 +312,7 @@ async def test_get_question_answer(request_msg_list, output_msg_str, row): type="chat", ), # Another superset - PartialQuestions( + v1_models.PartialQuestions( messages=["apple", "banana", "cherry"], timestamp=datetime.datetime(2023, 5, 2, 10, 0, 0), message_id="pqS2", @@ -319,14 +320,14 @@ async def test_get_question_answer(request_msg_list, output_msg_str, row): type="chat", ), # Subsets for pqS2 - PartialQuestions( + v1_models.PartialQuestions( messages=["banana"], timestamp=datetime.datetime(2023, 5, 2, 10, 0, 1), message_id="pqB1", provider="providerB", type="chat", ), - PartialQuestions( + v1_models.PartialQuestions( messages=["apple", "banana"], timestamp=datetime.datetime(2023, 5, 2, 10, 0, 3), message_id="pqB2", @@ -334,7 +335,7 @@ async def test_get_question_answer(request_msg_list, output_msg_str, row): type="chat", ), # Another item alone, not a subset nor superset - PartialQuestions( + v1_models.PartialQuestions( messages=["xyz"], timestamp=datetime.datetime(2023, 5, 3, 8, 0, 0), message_id="pqC1", @@ -342,7 +343,7 @@ async def test_get_question_answer(request_msg_list, output_msg_str, row): type="chat", ), # Different provider => should remain separate - PartialQuestions( + v1_models.PartialQuestions( messages=["hi", "welcome"], timestamp=datetime.datetime(2023, 5, 1, 9, 0, 10), message_id="pqProvDiff", @@ -394,7 +395,7 @@ def test_group_partial_messages(pq_list, expected_group_ids): # Execute grouped = _group_partial_messages(pq_list) - # Convert from list[list[PartialQuestions]] -> list[list[str]] + # Convert from list[list[v1_models.PartialQuestions]] -> list[list[str]] # so we can compare with expected_group_ids easily. grouped_ids = [[pq.message_id for pq in group] for group in grouped] @@ -406,3 +407,125 @@ def test_group_partial_messages(pq_list, expected_group_ids): is_matched = True break assert is_matched + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "alerts,expected_count,expected_ids", + [ + # Test Case 1: Non-secret alerts pass through unchanged + ( + [ + v1_models.Alert( + id="1", + prompt_id="p1", + code_snippet=None, + trigger_string="test1", + trigger_type="other-alert", + trigger_category="info", + timestamp=datetime.datetime(2023, 1, 1, 12, 0, 0), + ), + v1_models.Alert( + id="2", + prompt_id="p2", + code_snippet=None, + trigger_string="test2", + trigger_type="other-alert", + trigger_category="info", + timestamp=datetime.datetime(2023, 1, 1, 12, 0, 1), + ), + ], + 2, # Expected count + ["1", "2"], # Expected IDs preserved + ), + # Test Case 2: Duplicate secrets within 5 seconds - keep newer only + ( + [ + v1_models.Alert( + id="1", + prompt_id="p1", + code_snippet=None, + trigger_string="secret1 Context xyz", + trigger_type="codegate-secrets", + trigger_category="critical", + timestamp=datetime.datetime(2023, 1, 1, 12, 0, 0), + ), + v1_models.Alert( + id="2", + prompt_id="p2", + code_snippet=None, + trigger_string="secret1 Context abc", + trigger_type="codegate-secrets", + trigger_category="critical", + timestamp=datetime.datetime(2023, 1, 1, 12, 0, 3), + ), + ], + 1, # Expected count + ["2"], # Only newer alert ID + ), + # Test Case 3: Similar secrets beyond 5 seconds - keep both + ( + [ + v1_models.Alert( + id="1", + prompt_id="p1", + code_snippet=None, + trigger_string="secret1 Context xyz", + trigger_type="codegate-secrets", + trigger_category="critical", + timestamp=datetime.datetime(2023, 1, 1, 12, 0, 0), + ), + v1_models.Alert( + id="2", + prompt_id="p2", + code_snippet=None, + trigger_string="secret1 Context abc", + trigger_type="codegate-secrets", + trigger_category="critical", + timestamp=datetime.datetime(2023, 1, 1, 12, 0, 6), + ), + ], + 2, # Expected count + ["1", "2"], # Both alerts preserved + ), + # Test Case 4: Mix of secret and non-secret alerts + ( + [ + v1_models.Alert( + id="1", + prompt_id="p1", + code_snippet=None, + trigger_string="secret1 Context xyz", + trigger_type="codegate-secrets", + trigger_category="critical", + timestamp=datetime.datetime(2023, 1, 1, 12, 0, 0), + ), + v1_models.Alert( + id="2", + prompt_id="p2", + code_snippet=None, + trigger_string="non-secret alert", + trigger_type="other-alert", + trigger_category="info", + timestamp=datetime.datetime(2023, 1, 1, 12, 0, 1), + ), + v1_models.Alert( + id="3", + prompt_id="p3", + code_snippet=None, + trigger_string="secret1 Context abc", + trigger_type="codegate-secrets", + trigger_category="critical", + timestamp=datetime.datetime(2023, 1, 1, 12, 0, 3), + ), + ], + 2, # Expected count + ["2", "3"], # Non-secret alert and newest secret alert + ), + ], +) +async def test_remove_duplicate_alerts(alerts, expected_count, expected_ids): + result = await remove_duplicate_alerts(alerts) + assert len(result) == expected_count + result_ids = [alert.id for alert in result] + assert sorted(result_ids) == sorted(expected_ids) diff --git a/tests/pipeline/pii/test_pii_manager.py b/tests/pipeline/pii/test_pii_manager.py index 1cd5ab30..229b7314 100644 --- a/tests/pipeline/pii/test_pii_manager.py +++ b/tests/pipeline/pii/test_pii_manager.py @@ -44,7 +44,7 @@ def test_analyze_no_pii(self, manager, mock_analyzer): assert anonymized_text == text assert found_pii == [] assert manager.session_store is session_store - mock_analyzer.analyze.assert_called_once_with(text) + mock_analyzer.analyze.assert_called_once_with(text, context=None) def test_analyze_with_pii(self, manager, mock_analyzer): text = "My email is test@example.com" @@ -71,7 +71,7 @@ def test_analyze_with_pii(self, manager, mock_analyzer): assert found_pii == pii_details assert manager.session_store is session_store assert manager.session_store.mappings[placeholder] == "test@example.com" - mock_analyzer.analyze.assert_called_once_with(text) + mock_analyzer.analyze.assert_called_once_with(text, context=None) def test_restore_pii_no_session(self, manager, mock_analyzer): text = "Anonymized text"
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: