From 7e584b81a5bebd26ebec252159cb31a61c40463a Mon Sep 17 00:00:00 2001 From: Logan Solonche Date: Tue, 30 Jun 2026 09:42:48 -0400 Subject: [PATCH] feat: add VertexAI provider for Gemini models via GCP ADC Signed-off-by: Logan Solonche --- .env.example | 7 +- README.md | 14 +- model_registry.yaml | 21 +++ pyproject.toml | 1 + src/skillspector/providers/__init__.py | 7 +- .../providers/openai/model_registry.yaml | 20 +++ .../providers/vertexai/__init__.py | 20 +++ .../providers/vertexai/model_registry.yaml | 30 ++++ .../providers/vertexai/provider.py | 120 ++++++++++++++ tests/unit/test_providers.py | 95 +++++++++++ uv.lock | 155 ++++++++++++++++++ 11 files changed, 487 insertions(+), 3 deletions(-) create mode 100644 src/skillspector/providers/vertexai/__init__.py create mode 100644 src/skillspector/providers/vertexai/model_registry.yaml create mode 100644 src/skillspector/providers/vertexai/provider.py diff --git a/.env.example b/.env.example index 5e90ec6f..c969132c 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,7 @@ ENV=dev # options: dev|s # Active LLM provider. Selects which provider answers credentials, # metadata, and default-model lookups. Leave unset to default to nv_build. -# Options: openai | anthropic | anthropic_proxy | nv_build +# Options: openai | anthropic | anthropic_proxy | vertexai | nv_build SKILLSPECTOR_PROVIDER= # Provider credentials — set the one matching SKILLSPECTOR_PROVIDER (or @@ -28,6 +28,11 @@ ANTHROPIC_PROXY_API_KEY= # ANTHROPIC_PROXY_API_VERSION=vertex-2023-10-16 # optional; defaults to vertex-2023-10-16 # SKILLSPECTOR_SSL_VERIFY=false # set to false for internal/self-signed CAs +# For SKILLSPECTOR_PROVIDER=vertexai +GOOGLE_APPLICATION_CREDENTIALS= +GOOGLE_CLOUD_PROJECT= +GOOGLE_CLOUD_LOCATION= + # SkillSpector config SKILLSPECTOR_MODEL= # leave empty to use the active provider's bundled default (see README); set to override (e.g. gpt-5.2) # SKILLSPECTOR_MODEL_REGISTRY=./model_registry.yaml # optional override; defaults to each provider's bundled YAML in src/skillspector/providers/ diff --git a/README.md b/README.md index 4a09b50b..ad4e686b 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,7 @@ inference gateways. | `openai` | `OPENAI_API_KEY` (+ optional `OPENAI_BASE_URL`) | api.openai.com (or any OpenAI-compatible URL) | `gpt-5.4` | | `anthropic` | `ANTHROPIC_API_KEY` | api.anthropic.com | `claude-opus-4-6` | | `anthropic_proxy` | `ANTHROPIC_PROXY_API_KEY` + `ANTHROPIC_PROXY_ENDPOINT_URL` | Any Vertex-style raw-predict proxy | `claude-sonnet-4-6` | +| `vertexai` | `GOOGLE_CLOUD_PROJECT` + `GOOGLE_CLOUD_LOCATION` (+ optional `GOOGLE_APPLICATION_CREDENTIALS`) | VertexAI OpenAI-compat endpoint | `gemini-2.5-flash` | | `bedrock` | `AWS_PROFILE` (optional) + `AWS_REGION` — SigV4 via boto3 | AWS Bedrock Runtime | `us.anthropic.claude-sonnet-4-6-20250915-v1:0` | | `nv_build` | `NVIDIA_INFERENCE_KEY` | build.nvidia.com | `deepseek-ai/deepseek-v4-flash` | | `claude_cli` | _(none — uses local CLI auth)_ | local `claude` binary | `claude-sonnet-4-6` | @@ -226,6 +227,14 @@ export SKILLSPECTOR_PROVIDER=nv_build export NVIDIA_INFERENCE_KEY=nvapi-... skillspector scan ./my-skill/ +# VertexAI (Google Cloud) +export SKILLSPECTOR_PROVIDER=vertexai +export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json +export GOOGLE_CLOUD_PROJECT=your-project-id +export GOOGLE_CLOUD_LOCATION=us-central1 +export SKILLSPECTOR_MODEL=gemini-2.5-pro +skillspector scan ./my-skill/ + # Local Claude CLI — no API key; uses your existing `claude auth login` session # Requires: claude CLI installed and authenticated (claude auth login) export SKILLSPECTOR_PROVIDER=claude_cli @@ -526,7 +535,7 @@ Issues (2) | Variable | Description | Required | |----------|-------------|----------| -| `SKILLSPECTOR_PROVIDER` | Active LLM provider: `openai`, `anthropic`, `anthropic_proxy`, `bedrock`, `nv_build`, `claude_cli`, `codex_cli`, or `gemini_cli`. Each provider has its own bundled `model_registry.yaml` and default model (see the LLM Analysis table above). Defaults to `nv_build`. | Optional | +| `SKILLSPECTOR_PROVIDER` | Active LLM provider: `openai`, `anthropic`, `anthropic_proxy`, `vertexai`, `bedrock`, `nv_build`, `claude_cli`, `codex_cli`, or `gemini_cli`. Each provider has its own bundled `model_registry.yaml` and default model (see the LLM Analysis table above). Defaults to `nv_build`. | Optional | | `NVIDIA_INFERENCE_KEY` | Credential for the `nv_build` provider (build.nvidia.com). | Required for LLM analysis when `SKILLSPECTOR_PROVIDER=nv_build` | | `OPENAI_API_KEY` | Credential for the OpenAI provider (`SKILLSPECTOR_PROVIDER=openai`). Also serves as the tier-2 fallback in the credential waterfall when the active provider returns no credentials. | Required for LLM analysis when `SKILLSPECTOR_PROVIDER=openai` | | `OPENAI_BASE_URL` | Override the OpenAI endpoint (e.g. point at Ollama). | Optional | @@ -536,6 +545,9 @@ Issues (2) | `ANTHROPIC_PROXY_API_VERSION` | `anthropic_version` value sent in the request body (default: `vertex-2023-10-16`). | Optional | | `AWS_PROFILE` | Named AWS profile for the Bedrock provider — authenticates via SigV4 through boto3. When unset, the standard boto3 credential chain (env vars, instance metadata, SSO, etc.) resolves. | Optional (used when `SKILLSPECTOR_PROVIDER=bedrock`) | | `AWS_REGION` | AWS region for the Bedrock Runtime endpoint. Defaults to `us-west-2`. | Optional (used when `SKILLSPECTOR_PROVIDER=bedrock`) | +| `GOOGLE_APPLICATION_CREDENTIALS` | Path to a GCP service-account JSON key file. When unset, Application Default Credentials (ADC) resolve via the standard `google.auth.default()` chain. | Optional (used when `SKILLSPECTOR_PROVIDER=vertexai`) | +| `GOOGLE_CLOUD_PROJECT` | GCP project ID for the VertexAI endpoint. | Required when `SKILLSPECTOR_PROVIDER=vertexai` | +| `GOOGLE_CLOUD_LOCATION` | GCP region for the VertexAI endpoint (e.g. `us-central1`). | Required when `SKILLSPECTOR_PROVIDER=vertexai` | | `SKILLSPECTOR_MODEL` | Override the active provider's default model. See the LLM Analysis table for each provider's default. | Optional | | `SKILLSPECTOR_MODEL_REGISTRY` | Override the bundled per-provider YAML registry (`src/skillspector/providers//model_registry.yaml`) with a custom path. | Optional | | `SKILLSPECTOR_LOG_LEVEL` | Log level: `DEBUG`, `INFO`, `WARNING`, `ERROR` (default: `WARNING`). | Optional | diff --git a/model_registry.yaml b/model_registry.yaml index e1c2b8c6..f5288919 100644 --- a/model_registry.yaml +++ b/model_registry.yaml @@ -40,3 +40,24 @@ models: "openai/openai/gpt-5.3-chat": context_length: 128000 max_output_tokens: 16384 + + # Google Gemini models (via VertexAI or AI Studio OpenAI-compatible endpoints) + "gemini-2.0-flash": + context_length: 1048576 + max_output_tokens: 8192 + + "gemini-2.5-pro": + context_length: 1000000 + max_output_tokens: 65536 + + "gemini-2.5-flash": + context_length: 1048576 + max_output_tokens: 65535 + + "gemini-3.1-pro": + context_length: 1000000 + max_output_tokens: 65536 + + "gemini-3.5-flash": + context_length: 1048576 + max_output_tokens: 8192 diff --git a/pyproject.toml b/pyproject.toml index 00fc63c3..229534b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,6 +46,7 @@ dependencies = [ "boto3>=1.34.0", "langsmith>=0.7.30", "yara-python>=4.5.0", + "google-auth>=2.53.0", ] [project.optional-dependencies] diff --git a/src/skillspector/providers/__init__.py b/src/skillspector/providers/__init__.py index 809884dc..0c32ccfc 100644 --- a/src/skillspector/providers/__init__.py +++ b/src/skillspector/providers/__init__.py @@ -25,6 +25,7 @@ openai → OpenAIProvider (api.openai.com) anthropic → AnthropicProvider (api.anthropic.com) anthropic_proxy → AnthropicProxyProvider (Vertex-style raw-predict proxy) + vertexai → VertexAIProvider (VertexAI OpenAI-compat endpoint) bedrock → BedrockProvider (AWS Bedrock Runtime, SigV4) nv_build → NvBuildProvider (build.nvidia.com) claude_cli → ClaudeCLIProvider (local ``claude`` binary, no API key) @@ -89,6 +90,10 @@ def _select_active_provider() -> LLMProvider: from .anthropic_proxy import AnthropicProxyProvider return AnthropicProxyProvider() + if name == "vertexai": + from .vertexai import VertexAIProvider + + return VertexAIProvider() if name == "bedrock": from .bedrock import BedrockProvider @@ -123,7 +128,7 @@ def _select_active_provider() -> LLMProvider: raise ValueError( f"Unknown SKILLSPECTOR_PROVIDER: {name!r}. " - "Expected one of: openai, anthropic, anthropic_proxy, bedrock, nv_build, " + "Expected one of: openai, anthropic, anthropic_proxy, vertexai, bedrock, nv_build, " "claude_cli, codex_cli, gemini_cli, antigravity_cli (or unset)." ) diff --git a/src/skillspector/providers/openai/model_registry.yaml b/src/skillspector/providers/openai/model_registry.yaml index a4d26067..7826f9aa 100644 --- a/src/skillspector/providers/openai/model_registry.yaml +++ b/src/skillspector/providers/openai/model_registry.yaml @@ -12,3 +12,23 @@ models: "gpt-5.4": context_length: 1000000 max_output_tokens: 128000 + # Google Gemini models (via VertexAI or AI Studio OpenAI-compatible endpoints) + "gemini-2.0-flash": + context_length: 1048576 + max_output_tokens: 8192 + + "gemini-2.5-pro": + context_length: 1000000 + max_output_tokens: 65536 + + "gemini-2.5-flash": + context_length: 1048576 + max_output_tokens: 65535 + + "gemini-3.1-pro": + context_length: 1000000 + max_output_tokens: 65536 + + "gemini-3.5-flash": + context_length: 1048576 + max_output_tokens: 8192 \ No newline at end of file diff --git a/src/skillspector/providers/vertexai/__init__.py b/src/skillspector/providers/vertexai/__init__.py new file mode 100644 index 00000000..00991881 --- /dev/null +++ b/src/skillspector/providers/vertexai/__init__.py @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""VertexAI provider package (VertexAI OpenAI-compatibility endpoint).""" + +from .provider import REGISTRY_PATH, VertexAIProvider + +__all__ = ["REGISTRY_PATH", "VertexAIProvider"] diff --git a/src/skillspector/providers/vertexai/model_registry.yaml b/src/skillspector/providers/vertexai/model_registry.yaml new file mode 100644 index 00000000..3fafa8cc --- /dev/null +++ b/src/skillspector/providers/vertexai/model_registry.yaml @@ -0,0 +1,30 @@ +# Token-budget metadata for the VertexAIProvider. Bundled with the +# package; consulted whenever the active provider is VertexAIProvider. +# +# Format: +# models: +# "": +# context_length: # total context window in tokens (required) +# max_output_tokens: # model's max output cap (optional) + +models: + # Google Gemini models (via VertexAI) + "gemini-2.0-flash": + context_length: 1048576 + max_output_tokens: 8192 + + "gemini-2.5-pro": + context_length: 1000000 + max_output_tokens: 65536 + + "gemini-2.5-flash": + context_length: 1048576 + max_output_tokens: 65535 + + "gemini-3.1-pro": + context_length: 1000000 + max_output_tokens: 65536 + + "gemini-3.5-flash": + context_length: 1048576 + max_output_tokens: 8192 diff --git a/src/skillspector/providers/vertexai/provider.py b/src/skillspector/providers/vertexai/provider.py new file mode 100644 index 00000000..76604675 --- /dev/null +++ b/src/skillspector/providers/vertexai/provider.py @@ -0,0 +1,120 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""VertexAI provider — Gemini models via VertexAI OpenAI-compatible endpoint. + +Reads ``GOOGLE_APPLICATION_CREDENTIALS``, ``GOOGLE_CLOUD_PROJECT``, and +``GOOGLE_CLOUD_LOCATION`` for credentials and constructs the VertexAI +OpenAI-compatible endpoint URL. Uses Google Cloud Application Default +Credentials (ADC) to generate access tokens. Defaults to Gemini 2.5 Flash. +""" + +from __future__ import annotations + +import os +from pathlib import Path + +import google.auth +import google.auth.transport.requests +from langchain_core.language_models.chat_models import BaseChatModel + +from skillspector.providers import registry +from skillspector.providers.chat_models import create_openai_compatible_chat_model + +REGISTRY_PATH = str(Path(__file__).with_name("model_registry.yaml")) + + +class VertexAIProvider: + """Stock VertexAI credentials + bundled-YAML metadata provider.""" + + DEFAULT_MODEL = "gemini-2.5-flash" + SLOT_DEFAULTS: dict[str, str] = {} + + WIRE_MODEL_PREFIX = "google/" + + def resolve_credentials(self) -> tuple[str, str | None] | None: + """Return ``(access_token, base_url)`` from Google Cloud credentials. + + Uses Application Default Credentials (ADC) via ``google.auth.default()``. + The access token is refreshed from the credentials object and returned + as the API key for the OpenAI-compatible client. + + Returns ``None`` when required environment variables are not set. + + Raises: + google.auth.exceptions.DefaultCredentialsError: When credentials + are configured but invalid or malformed. + ValueError: When token refresh fails. + """ + + project_id = os.environ.get("GOOGLE_CLOUD_PROJECT", "").strip() + location = os.environ.get("GOOGLE_CLOUD_LOCATION", "").strip() + + if not project_id or not location: + return None + + credentials, _ = google.auth.default( + scopes=["https://www.googleapis.com/auth/cloud-platform"] + ) + + credentials.refresh(google.auth.transport.requests.Request()) + + access_token = credentials.token + if not access_token: + raise ValueError( + "Failed to obtain access token from Google Cloud credentials. " + "Ensure GOOGLE_APPLICATION_CREDENTIALS points to a valid " + "service account key file." + ) + + base_url = ( + f"https://{location}-aiplatform.googleapis.com/v1beta1/" + f"projects/{project_id}/locations/{location}/endpoints/openapi" + ) + + return access_token, base_url + + def create_chat_model( + self, + model: str, + *, + max_tokens: int, + timeout: float | None = 120, + ) -> BaseChatModel | None: + """Create ``ChatOpenAI`` for the VertexAI OpenAI-compatible endpoint. + + The endpoint requires model names prefixed with ``google/`` + (e.g. ``google/gemini-2.5-flash``). The prefix is applied here + at the wire boundary so that registry lookups and token-budget + calculations continue to use bare model labels. + """ + wire_model = model if model.startswith(self.WIRE_MODEL_PREFIX) else f"{self.WIRE_MODEL_PREFIX}{model}" + return create_openai_compatible_chat_model( + model=wire_model, + credentials=self.resolve_credentials(), + max_tokens=max_tokens, + timeout=timeout, + ) + + def get_context_length(self, model: str) -> int | None: + return registry.lookup_context_length(REGISTRY_PATH, model) + + def get_max_output_tokens(self, model: str) -> int | None: + return registry.lookup_max_output_tokens(REGISTRY_PATH, model) + + def resolve_model(self, slot: str = "default") -> str: + """Resolve model: ``SKILLSPECTOR_MODEL`` env > slot default > ``DEFAULT_MODEL``.""" + user_input = os.environ.get("SKILLSPECTOR_MODEL", "").strip() + return user_input or self.SLOT_DEFAULTS.get(slot, "") or self.DEFAULT_MODEL diff --git a/tests/unit/test_providers.py b/tests/unit/test_providers.py index 61937409..f9cf02b4 100644 --- a/tests/unit/test_providers.py +++ b/tests/unit/test_providers.py @@ -23,6 +23,7 @@ from __future__ import annotations import sys +from unittest.mock import MagicMock, patch import pytest from langchain_anthropic import ChatAnthropic @@ -45,6 +46,7 @@ from skillspector.providers.gemini_cli import GeminiCLIProvider from skillspector.providers.nv_build import BUILD_BASE_URL, NvBuildProvider from skillspector.providers.openai import OpenAIProvider +from skillspector.providers.vertexai import VertexAIProvider try: from skillspector.providers.nv_inference import ( @@ -74,6 +76,9 @@ def _clean_provider_env(monkeypatch: pytest.MonkeyPatch): monkeypatch.delenv("SKILLSPECTOR_MODEL", raising=False) monkeypatch.delenv("SKILLSPECTOR_MODEL_REGISTRY", raising=False) monkeypatch.delenv("SKILLSPECTOR_PROVIDER", raising=False) + monkeypatch.delenv("GOOGLE_APPLICATION_CREDENTIALS", raising=False) + monkeypatch.delenv("GOOGLE_CLOUD_PROJECT", raising=False) + monkeypatch.delenv("GOOGLE_CLOUD_LOCATION", raising=False) registry._load.cache_clear() yield registry._load.cache_clear() @@ -275,6 +280,96 @@ def test_metadata_known_models(self) -> None: assert provider.get_context_length("claude-sonnet-4-6") == 1_000_000 +class TestVertexAIProvider: + """VertexAI provider — credentials, model prefix, and bundled YAML metadata.""" + + def test_returns_none_without_env_vars(self) -> None: + assert VertexAIProvider().resolve_credentials() is None + + def test_returns_none_with_partial_env(self, monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setenv("GOOGLE_CLOUD_PROJECT", "my-project") + assert VertexAIProvider().resolve_credentials() is None + + @patch("skillspector.providers.vertexai.provider.google.auth.default") + @patch("skillspector.providers.vertexai.provider.google.auth.transport.requests.Request") + def test_resolves_credentials( + self, + mock_request: MagicMock, + mock_auth_default: MagicMock, + monkeypatch: pytest.MonkeyPatch, + ) -> None: + mock_creds = MagicMock() + mock_creds.token = "fake-access-token" + mock_auth_default.return_value = (mock_creds, "default-project") + monkeypatch.setenv("GOOGLE_CLOUD_PROJECT", "my-project") + monkeypatch.setenv("GOOGLE_CLOUD_LOCATION", "us-central1") + + creds = VertexAIProvider().resolve_credentials() + assert creds is not None + token, base_url = creds + assert token == "fake-access-token" + assert "us-central1" in base_url + assert "my-project" in base_url + assert base_url.endswith("/endpoints/openapi") + + @patch("skillspector.providers.vertexai.provider.google.auth.default") + @patch("skillspector.providers.vertexai.provider.google.auth.transport.requests.Request") + def test_create_chat_model_prefixes_model_with_google( + self, + mock_request: MagicMock, + mock_auth_default: MagicMock, + monkeypatch: pytest.MonkeyPatch, + ) -> None: + mock_creds = MagicMock() + mock_creds.token = "fake-access-token" + mock_auth_default.return_value = (mock_creds, "default-project") + monkeypatch.setenv("GOOGLE_CLOUD_PROJECT", "my-project") + monkeypatch.setenv("GOOGLE_CLOUD_LOCATION", "us-central1") + + llm = VertexAIProvider().create_chat_model("gemini-2.5-flash", max_tokens=123) + assert isinstance(llm, ChatOpenAI) + assert llm.model_name == "google/gemini-2.5-flash" + assert llm.max_tokens == 123 + + @patch("skillspector.providers.vertexai.provider.google.auth.default") + @patch("skillspector.providers.vertexai.provider.google.auth.transport.requests.Request") + def test_create_chat_model_does_not_double_prefix( + self, + mock_request: MagicMock, + mock_auth_default: MagicMock, + monkeypatch: pytest.MonkeyPatch, + ) -> None: + mock_creds = MagicMock() + mock_creds.token = "fake-access-token" + mock_auth_default.return_value = (mock_creds, "default-project") + monkeypatch.setenv("GOOGLE_CLOUD_PROJECT", "my-project") + monkeypatch.setenv("GOOGLE_CLOUD_LOCATION", "us-central1") + + llm = VertexAIProvider().create_chat_model("google/gemini-2.5-flash", max_tokens=123) + assert isinstance(llm, ChatOpenAI) + assert llm.model_name == "google/gemini-2.5-flash" + + def test_create_chat_model_returns_none_without_credentials(self) -> None: + assert VertexAIProvider().create_chat_model("gemini-2.5-flash", max_tokens=123) is None + + def test_metadata_known_model_from_bundled_yaml(self) -> None: + provider = VertexAIProvider() + assert provider.get_context_length("gemini-2.5-flash") == 1_048_576 + assert provider.get_max_output_tokens("gemini-2.5-flash") == 65_535 + + def test_metadata_unknown_model_returns_none(self) -> None: + provider = VertexAIProvider() + assert provider.get_context_length("unknown-model") is None + assert provider.get_max_output_tokens("unknown-model") is None + + def test_resolve_model_default_when_no_env(self) -> None: + assert VertexAIProvider().resolve_model() == "gemini-2.5-flash" + + def test_resolve_model_env_overrides_default(self, monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setenv("SKILLSPECTOR_MODEL", "gemini-2.5-pro") + assert VertexAIProvider().resolve_model() == "gemini-2.5-pro" + + class TestOpenAICompatibleConstructor: """The shared OpenAI-compatible chat-model constructor.""" diff --git a/uv.lock b/uv.lock index 08d247e7..1ee5511a 100644 --- a/uv.lock +++ b/uv.lock @@ -166,6 +166,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/95/c1/84fc6811122f54b20de2e5afb312ee07a3a47a328755587d1e505475239b/blockbuster-1.5.26-py3-none-any.whl", hash = "sha256:f8e53fb2dd4b6c6ec2f04907ddbd063ca7cd1ef587d24448ef4e50e81e3a79bb", size = 13226, upload-time = "2025-12-05T10:43:48.778Z" }, ] +[[package]] +name = "boto3" +version = "1.43.37" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, + { name = "jmespath" }, + { name = "s3transfer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fa/8b/281ca08c796322a36a639b76c714dc4c4323cab4563a492e6a923aa5f15d/boto3-1.43.37.tar.gz", hash = "sha256:cf7e75963229b337d1b0e37c46de6f3c2c2290d186157729c8e7afb12909bfc0", size = 112674, upload-time = "2026-06-29T20:29:39.273Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/48/c740abb7ba90d89ef63cf766c8e07d72e6422b3cf68aa4dccf0a83efed93/boto3-1.43.37-py3-none-any.whl", hash = "sha256:f409f931e836f2f24e168e8f93901010cb8055c7f2ddcfcfbd72b25f8c4e306c", size = 140032, upload-time = "2026-06-29T20:29:36.409Z" }, +] + +[[package]] +name = "botocore" +version = "1.43.37" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "python-dateutil" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c4/a8/3409b5df7e6a562be82e409ba5a976e7ac3df8d5567552c23d44b367a40b/botocore-1.43.37.tar.gz", hash = "sha256:46a7982815579cfe8c7851036b1f51237e35e7937456341df55bc5c36a316145", size = 15646119, upload-time = "2026-06-29T20:29:25.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/64/49313b38d675f4004fb736d2a4293b72504eac5380fc21b6e4a8660824ad/botocore-1.43.37-py3-none-any.whl", hash = "sha256:8b7e8408aa7eca7dca9ae9824fb7677daf64d40ed675366ed7b9248470d08757", size = 15333748, upload-time = "2026-06-29T20:29:20.459Z" }, +] + [[package]] name = "build" version = "1.5.0" @@ -633,6 +661,19 @@ version = "0.1.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e6/79/d4f20e91327c98096d605646bdc6a5ffedae820f38d378d3515c42ec5e60/forbiddenfruit-0.1.4.tar.gz", hash = "sha256:e3f7e66561a29ae129aac139a85d610dbf3dd896128187ed5454b6421f624253", size = 43756, upload-time = "2021-01-16T21:03:35.401Z" } +[[package]] +name = "google-auth" +version = "2.55.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "pyasn1-modules" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/6f/f3f4ac177c67bbee8fe8e88f2ab4f36af88c44a096e165c5217accf6e5d3/google_auth-2.55.1.tar.gz", hash = "sha256:fb2d9b730f2c9b8d326ec8d7222f21aef2ead15bf0513793d6442485d87af0a1", size = 349527, upload-time = "2026-06-25T23:39:27.182Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl", hash = "sha256:eada68dfd52b3b81191827601e2a0c3fa12540c818534b630ddc5355769c3995", size = 252349, upload-time = "2026-06-25T23:38:52.946Z" }, +] + [[package]] name = "googleapis-common-protos" version = "1.75.0" @@ -973,6 +1014,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c8/8d/302cb2057b7513327b4d575cff6b1d066ee6431a5357fc3f8867cd684406/jiter-0.15.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54d5d6090cdc1b7c9e780dfb04949a990adb1e301a2fc0bbcee7de4638d33f9a", size = 344469, upload-time = "2026-05-19T10:09:46.864Z" }, ] +[[package]] +name = "jmespath" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377, upload-time = "2026-01-22T16:35:26.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" }, +] + [[package]] name = "jsonpatch" version = "1.33" @@ -1083,6 +1133,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/94/bf/78c71bdd7b9ec6fcd6ca45114d5910bfbad2fba21e5223523e793a17520d/langchain_anthropic-1.4.7-py3-none-any.whl", hash = "sha256:2e9d9dd4cb66de19394d7a9d552e1dbf2cd3c1da9f799a0c372b5fc84e298d8f", size = 51978, upload-time = "2026-06-22T22:56:04.349Z" }, ] +[[package]] +name = "langchain-aws" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "boto3" }, + { name = "langchain-core" }, + { name = "numpy" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/c6/4065908dc2f113324d1ac31ecf5c907a23863f7aeaab7b9361efd7109563/langchain_aws-1.6.1.tar.gz", hash = "sha256:b5b054f48e2697fa1b96733e9de2accfdd1a4948d9b4e3712e8180c4585cfd2f", size = 538265, upload-time = "2026-06-25T19:02:23.364Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/ab/d85b915c12394385459bb536202227d0fd81377929d71b16f177559ba074/langchain_aws-1.6.1-py3-none-any.whl", hash = "sha256:a121f687b36678239dd96ee9d0503a0b7d5fc4570b3af6d19983ef6ebfaf115e", size = 206315, upload-time = "2026-06-25T19:02:21.848Z" }, +] + [[package]] name = "langchain-core" version = "1.4.8" @@ -1557,6 +1622,57 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/e5/7cafee2f0413ca4cb0ef3bd111e94d408a48810008b283ad8aee00dd1809/nh3-0.3.6-cp38-abi3-win_arm64.whl", hash = "sha256:69f365963f63a1e9bff53bdbb3c542c7c2efed3e163c9d5d83a772a2ac468c21", size = 603060, upload-time = "2026-06-22T00:47:00.596Z" }, ] +[[package]] +name = "numpy" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/05/3d27272d30698dc0ecb7fdfaa41ad70303b444f81722bb99bce1d818638a/numpy-2.5.0.tar.gz", hash = "sha256:5a129578019311b6e56bdd714250f19b518f7dceeeb8d1af5490f4942d3f891c", size = 20652461, upload-time = "2026-06-21T20:57:51.95Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/0a/11486d02add7b1384dff7374d124b1cfbb0ee864dcc9f6a2c0380638cf84/numpy-2.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:489780423903667933b4ed6197b6ec3b75ea5dd17d1d8f0f38d798feb6921561", size = 16789987, upload-time = "2026-06-21T20:56:16.657Z" }, + { url = "https://files.pythonhosted.org/packages/55/b2/285f48640a181947b4587a3766d21ec1eaa7fea833d4b49957e09da467a2/numpy-2.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ece55976ced6bca95a03ae2839e2e5ccffe8eb6a3e7022415645eb154a81e4e6", size = 11760322, upload-time = "2026-06-21T20:56:19.813Z" }, + { url = "https://files.pythonhosted.org/packages/dd/67/b032db1eb03ca30d16eda3b0c22aaa615338b9263c2fd559d0f29451aca4/numpy-2.5.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:c83b664b0e6eee9594fa920cf0639d8af796606d3fad6cc70180c87e4b97c7be", size = 5319605, upload-time = "2026-06-21T20:56:22.173Z" }, + { url = "https://files.pythonhosted.org/packages/b9/83/03fc7300c7c6b6c84c487b1dc80d322817b95fbd1f4dd57a85e23b7198de/numpy-2.5.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:bf80333980bf37f523341ddd72c783f39d6829ec7736b9eb99086388a2d52cc2", size = 6653628, upload-time = "2026-06-21T20:56:23.914Z" }, + { url = "https://files.pythonhosted.org/packages/82/49/2ec21730bc63ccfda829323f7040a8ed4715b3852ce658689cf74ee96a8c/numpy-2.5.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1a4874217b36d5ac8fc876f52e39df56f8182c88463e9e2dceabf7ca8b7efb8", size = 15153691, upload-time = "2026-06-21T20:56:25.631Z" }, + { url = "https://files.pythonhosted.org/packages/bb/6b/f4a3d0637692c49da8ef99d72d52526f92e0a8d6ac4f0ca9f31441b9d9ea/numpy-2.5.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aaa760137137e8d3c920d27927748215b56014f92667dc9b6c27dfc61249255a", size = 16660066, upload-time = "2026-06-21T20:56:28.009Z" }, + { url = "https://files.pythonhosted.org/packages/3a/2f/c354ec86d1f3f5c19649463b0d39652e160736e5b0a4cd18dff0576715c4/numpy-2.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7174ce8265fc7f7417d171c9ea8fe905220748893ea67a2a7abe726ec331c4b0", size = 16514638, upload-time = "2026-06-21T20:56:30.26Z" }, + { url = "https://files.pythonhosted.org/packages/06/34/43efdcb319988648580f93c11f1ae82cf7e2faa74925e98e454ae3aa95f8/numpy-2.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b8c3daaf99de52415d20b42f8e8155c78642cb04207d02f9d317a0dcf1b3fb54", size = 18419647, upload-time = "2026-06-21T20:56:32.41Z" }, + { url = "https://files.pythonhosted.org/packages/71/e2/f5d1676b1d7fb682eb5e9a1641e7ebd2414b3216c370661d1029778908b4/numpy-2.5.0-cp312-cp312-win32.whl", hash = "sha256:6206db0af545d73d068add6d992279145f158428d1da6cc49adc4b630c5d6ee5", size = 6056688, upload-time = "2026-06-21T20:56:34.657Z" }, + { url = "https://files.pythonhosted.org/packages/8f/7c/48f115d1c58a34032facebcd51fdf2d02df2c51d4a46a81dd1197bb2ea6b/numpy-2.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:6f2d6873e2940c860a309d21e25b1e69af6aaffdd80aa056b04c16380db1c4f2", size = 12419237, upload-time = "2026-06-21T20:56:36.24Z" }, + { url = "https://files.pythonhosted.org/packages/86/26/2e0882f4044d1b1a1b63e875151fb2393389032022a8b7f5657a7996d3b2/numpy-2.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:a55e1eb2bca2cfd17a16b213c99dfc8502d47b0d494224d2122277d0400935ca", size = 10339912, upload-time = "2026-06-21T20:56:38.733Z" }, + { url = "https://files.pythonhosted.org/packages/8a/33/07675aaad7f26ea013d5e884d9a0d784b79c6bd7566c333f5a52fa3c610b/numpy-2.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:520e6b8be0a4b65840ac8090d4f51cef4bed66e2b0894d5a520f099adc24a9b2", size = 16784890, upload-time = "2026-06-21T20:56:40.799Z" }, + { url = "https://files.pythonhosted.org/packages/85/4b/953118a730ee3b35e28645e0eb4cf9beec5bdbb954e1ac2f5fcefba6bbc3/numpy-2.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:146b81cdd3967fdb6beca8ba25f00c58741d8f3cbd797f55af0fbe0bfec3469c", size = 11754584, upload-time = "2026-06-21T20:56:43.094Z" }, + { url = "https://files.pythonhosted.org/packages/44/9b/56dd530c367c74ae17411027cea4135ca57e1e0583bf5594cee18bd83217/numpy-2.5.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:126b88d95e8ff9b00c9e717aa540469f21d6180162f84c0caec51b16215d49cd", size = 5313904, upload-time = "2026-06-21T20:56:45.503Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b0/bcd672edad27ecca7da1f7bb0ce72cd1706a4f2d79ae94990afc97c13e1c/numpy-2.5.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d4313cef1594c5ce46c31b6e54e918338f63f16ee9322304e8c9114d6d81c8bd", size = 6648504, upload-time = "2026-06-21T20:56:47.567Z" }, + { url = "https://files.pythonhosted.org/packages/80/9e/15cdfcbd30a1544a46c9e487a00df331c4672450216538705a9e51fa6710/numpy-2.5.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:750fb097caf26fa878746d9d119f6f9da12dedcbff1eea966c3e3447647c4a9e", size = 15150086, upload-time = "2026-06-21T20:56:49.352Z" }, + { url = "https://files.pythonhosted.org/packages/32/4e/8d7656ccaab3e81e97258b8a9bc5f0c8502513a92fb4ceb0a2cbfebc17bf/numpy-2.5.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3893adc2dc7c0412ba76777db55a049215d99c9aa3113003be8f49f4f1290ab9", size = 16647250, upload-time = "2026-06-21T20:56:51.542Z" }, + { url = "https://files.pythonhosted.org/packages/3c/81/97060281b602ed07f21b12f4ec409eac1f75a2f91fbc829ed8b2becf3ad4/numpy-2.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:835e454dd99b238cdc5a3f63bce2371296f5ebc53ca1e0f8e6ddbb6d92a29aab", size = 16512864, upload-time = "2026-06-21T20:56:55.401Z" }, + { url = "https://files.pythonhosted.org/packages/33/ab/4496208146911f8d8ddb54f68a972aafa6c8d44babcb2ea03b0e5cc87c9d/numpy-2.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f9836778081a0a3c02a6a21493f3e9f5b311f8d2541934f31f05583dc999ea4", size = 18408407, upload-time = "2026-06-21T20:56:57.75Z" }, + { url = "https://files.pythonhosted.org/packages/d4/9f/a4df67c181e4ee8b467aa3332dc2db10fd5c515136831302f3ca48bc0a01/numpy-2.5.0-cp313-cp313-win32.whl", hash = "sha256:0b525be4744b60bb0557ac872d53ef07d085b5f39622bc579c98d3809d05b988", size = 6054431, upload-time = "2026-06-21T20:57:00.016Z" }, + { url = "https://files.pythonhosted.org/packages/30/53/491e1c47c55b62ccc6a63c1c5b8635c73fc2258dddeb9bda27cae4a0ae96/numpy-2.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:44353e2878930039db472b99dc353d749826e4010bd4d2a7f835e94a97a5c748", size = 12414420, upload-time = "2026-06-21T20:57:01.815Z" }, + { url = "https://files.pythonhosted.org/packages/eb/4a/25c2906f541e9d9f4c5769764db732e6627be91a13f4724fa10634d77db4/numpy-2.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:48f54b00711f83a5f796b70c518e8c2b3c5848dda03a54911f23eb68519b9b60", size = 10339533, upload-time = "2026-06-21T20:57:03.961Z" }, + { url = "https://files.pythonhosted.org/packages/86/ad/abc44aaceaf7b17ee1edde2bbb4458da591bc79574cffff50c4bb35f00d1/numpy-2.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f27582c55ba4c750b7c58c8faf021d2cd9324a662b466229db8a417b41368af9", size = 16783807, upload-time = "2026-06-21T20:57:06.253Z" }, + { url = "https://files.pythonhosted.org/packages/5d/39/b72e168daf9c00fb20c9fc996d00437ccecdef3102387775d29d7a62576d/numpy-2.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:28e7137057d551e4a83c4ae414e3451f50568409db7569aacc7f9811ee06a446", size = 11765215, upload-time = "2026-06-21T20:57:08.547Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a0/8400a9c0e3625182347593f5e1f57da9a617a534794805c8df5518154ddc/numpy-2.5.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:e1da54b53e75cd9fcfc23efcc7edab2c6aecf97b6037566d8a0fe804af8ec57c", size = 5324493, upload-time = "2026-06-21T20:57:11.012Z" }, + { url = "https://files.pythonhosted.org/packages/f6/8c/0d104deaa0401c93395a629ec902891618a2eff76d19229139cb5a887bfc/numpy-2.5.0-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:694d8f74e156f7fd01179f1aa8faa2f648ab6ae0f70b6c3fe57a03249aea2303", size = 6645211, upload-time = "2026-06-21T20:57:12.919Z" }, + { url = "https://files.pythonhosted.org/packages/6a/d9/4a4a628c812750363786afc3d33492709a5cd64b215469c16b0f6c7bb811/numpy-2.5.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1a7569a7b53c77716f036bb28cb1c91f166a26ec7d9502cd1e4bdfe502fdec22", size = 15166004, upload-time = "2026-06-21T20:57:14.717Z" }, + { url = "https://files.pythonhosted.org/packages/a0/5e/2a902317d7fc4aa93236e80c932662dadfc459b323d758329e01775125e1/numpy-2.5.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:39a0433bd4086ebd462960cf375e19195bb07b53dc1d87dd5fcf47ad78576f03", size = 16650797, upload-time = "2026-06-21T20:57:16.906Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a0/a0090e6329f4ca5992c07847bb579c5259a19953dc57255bb08793142ffb/numpy-2.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:929f0c79ac38bcbd7154fe631dc907abfeddbcc5027a896bd1f7767323271e7a", size = 16524647, upload-time = "2026-06-21T20:57:19.165Z" }, + { url = "https://files.pythonhosted.org/packages/5e/7d/6caf27734c42b65837e7461ed0dbbd6b6fc835060c9714ec59d673bb383a/numpy-2.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cc4f247a47bbf070bfd70be53ccdcf47b800af563535e7bbe172322197c30e21", size = 18411841, upload-time = "2026-06-21T20:57:21.638Z" }, + { url = "https://files.pythonhosted.org/packages/13/dc/26edadbd812536769a82c2e9e002234e33feb5da43061d47a044f6d309b7/numpy-2.5.0-cp314-cp314-win32.whl", hash = "sha256:5dc71423499fab3f46f7a7201155ade1669ea101f2f429d332df9e72f8161731", size = 6106361, upload-time = "2026-06-21T20:57:23.844Z" }, + { url = "https://files.pythonhosted.org/packages/f2/9e/4dd1459282229a72d92dece2ae9138e5cac94a72263a7ceb48f37434c925/numpy-2.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:ebb81d9d5443e0309d6c54894c3fbed74ad7da0714352a67b6d773cd189eae73", size = 12551749, upload-time = "2026-06-21T20:57:25.945Z" }, + { url = "https://files.pythonhosted.org/packages/05/a7/6bc6384c080b86c7f6c85c5bc5b540b24f4f679cd144791d99574e90d462/numpy-2.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:3b94d0d0deceebfad3e67ae5c0e5eb87371e8f7a0581cd04a779928c2450cf1e", size = 10617072, upload-time = "2026-06-21T20:57:28.175Z" }, + { url = "https://files.pythonhosted.org/packages/86/6b/4a2b71d66ada5608ae02b63f150dfad520f6940721cb7f029ad270befc0e/numpy-2.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:22f3d43e362d650bc39db1f17851302874a148ca95ba6981c1dfb5fa6862f35b", size = 11881067, upload-time = "2026-06-21T20:57:30.104Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b2/d365eb40a20efb49d67e9feb90494ed8511282ee1f5fa16006675c65397d/numpy-2.5.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:243563efb4cd7528a264567e9fd206c87826457322521d06206a00bfa316c927", size = 5440290, upload-time = "2026-06-21T20:57:32.193Z" }, + { url = "https://files.pythonhosted.org/packages/fa/5e/e9c03188de5f9b767e46a8fe988bcfd3efad066a4a3fda8b9cb11a93f895/numpy-2.5.0-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:84881d825ca75249b189bbee875fcfe3238aa5c479e6100893cda566e8e86826", size = 6748371, upload-time = "2026-06-21T20:57:33.933Z" }, + { url = "https://files.pythonhosted.org/packages/fd/1d/68c186a38a5027bae2c4ddd5ea681fdaf8b4d30fb7301def6d8ad270390f/numpy-2.5.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cda12aa4779d42b8771180aba759c96f527d43446d8f380ab59e2b35e8489efd", size = 15214643, upload-time = "2026-06-21T20:57:35.677Z" }, + { url = "https://files.pythonhosted.org/packages/8c/67/73f67b7c7e20635baae9c4c3ead4ae7326a005900297a6110971abd62eb5/numpy-2.5.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c0121101093d2bd74981b10f8837d78e794a8ff57834eb27179f49e1ba11ac6", size = 16690128, upload-time = "2026-06-21T20:57:38.159Z" }, + { url = "https://files.pythonhosted.org/packages/eb/05/d4c1fb0c46d02a27d6b2b8b319a78c90937acec8631c1641874670b31e6f/numpy-2.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d371c92cfa09da00022f501ab67fafaea813d752eb30ac44336d45b1e5b0268a", size = 16577902, upload-time = "2026-06-21T20:57:40.447Z" }, + { url = "https://files.pythonhosted.org/packages/9e/1d/771c797d50fa26e4888989cccf1d50ee51f530d4e455ad2692dcb64fa711/numpy-2.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9990713e9c38154c6861e7547f1e3fc7a87e75ff09bab24ef1cc81d81c2835e9", size = 18452814, upload-time = "2026-06-21T20:57:42.875Z" }, + { url = "https://files.pythonhosted.org/packages/e8/46/52fc0d2a68d7643f0f149eeea5a5d8ea2a3507056ac8afa83c9212606e8b/numpy-2.5.0-cp314-cp314t-win32.whl", hash = "sha256:edadfbd4794b1086c0d822f81863e8a68fc129d132fd0bb9e31e955d7fbbbdb7", size = 6253168, upload-time = "2026-06-21T20:57:45.101Z" }, + { url = "https://files.pythonhosted.org/packages/2a/be/6c8d1118b5f13b2881dc095d5b345de19c6638b8959c17409b6eff84c8aa/numpy-2.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f7e5fa4382967ae6548bd2f174219afb908e294b0d5f625af01166edd5f7d9aa", size = 12736286, upload-time = "2026-06-21T20:57:46.935Z" }, + { url = "https://files.pythonhosted.org/packages/fd/6a/d3a169aaf8536cf228d56a09e04bcb713a2fe4410d4e2105b9419b5a9c89/numpy-2.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:016623417bb330d719d579daf2d6b9a01ddc52e41a9ed61a47f39fde46dcd865", size = 10686451, upload-time = "2026-06-21T20:57:49.313Z" }, +] + [[package]] name = "openai" version = "2.44.0" @@ -1867,6 +1983,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901", size = 170656, upload-time = "2026-03-18T19:04:59.826Z" }, ] +[[package]] +name = "pyasn1" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" }, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, +] + [[package]] name = "pycparser" version = "3.0" @@ -2503,6 +2640,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/30/66/9a73695e31eaee04f35d8475998bf8ab354465f9c638936d76111603dcc5/ruff-0.15.19-py3-none-win_arm64.whl", hash = "sha256:6c6b607466e47349332eb1d9be52fb1467423fc07c217341af41cd0f3f0573be", size = 11376779, upload-time = "2026-06-24T01:10:34.465Z" }, ] +[[package]] +name = "s3transfer" +version = "0.19.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f6/94/dcdaeb1713cab9c84def276cfac7388b17c7d9855bbcfe88d77e4dbafd44/s3transfer-0.19.0.tar.gz", hash = "sha256:ce436931687addc4c1712d52d40b32f53e88315723f107ffa20ba82b05a0f685", size = 165171, upload-time = "2026-06-16T19:44:51.599Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/5f/4c174edad94f82de888ac00a5ddd8d07b35609b6c94f0bdf4d74af57703e/s3transfer-0.19.0-py3-none-any.whl", hash = "sha256:777cc2415536f1debadb5c2ef7779275d0fc0fe0e042411cdd6caebeb2685262", size = 90101, upload-time = "2026-06-16T19:44:50.439Z" }, +] + [[package]] name = "secretstorage" version = "3.5.0" @@ -2548,8 +2697,11 @@ name = "skillspector" version = "2.3.7" source = { editable = "." } dependencies = [ + { name = "boto3" }, + { name = "google-auth" }, { name = "httpx" }, { name = "langchain-anthropic" }, + { name = "langchain-aws" }, { name = "langchain-core" }, { name = "langchain-openai" }, { name = "langgraph" }, @@ -2581,9 +2733,12 @@ mcp = [ [package.metadata] requires-dist = [ + { name = "boto3", specifier = ">=1.34.0" }, { name = "build", marker = "extra == 'dev'", specifier = ">=1.4.0" }, + { name = "google-auth", specifier = ">=2.53.0" }, { name = "httpx", specifier = ">=0.28.0" }, { name = "langchain-anthropic", specifier = ">=1.4.5" }, + { name = "langchain-aws", specifier = ">=0.2.0" }, { name = "langchain-core", specifier = ">=1.2.17" }, { name = "langchain-openai", specifier = ">=1.1.10" }, { name = "langgraph", specifier = ">=1.0.10" },