diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 1dece1ec7..8de8cf506 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -69,8 +69,8 @@ jobs: with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} - allowed_non_write_users: Copilot,copilot,jules[bot],jules - allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],copilot,github-actions,gemini[bot],claude[bot],jules[bot]" + allowed_non_write_users: Copilot + allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],copilot,github-actions,gemini[bot],claude[bot]" trigger_phrase: "@claude" assignee_trigger: claude[bot] label_trigger: claude @@ -105,8 +105,8 @@ jobs: with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} - allowed_non_write_users: Copilot,copilot,jules[bot],jules - allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],copilot,github-actions,gemini[bot],claude[bot],jules[bot]" + allowed_non_write_users: Copilot + allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],copilot,github-actions,gemini[bot],claude[bot]" trigger_phrase: "@claude" assignee_trigger: claude label_trigger: claude @@ -142,8 +142,6 @@ jobs: with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} - allowed_non_write_users: Copilot,copilot,jules[bot],jules - allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],copilot,github-actions,gemini[bot],claude[bot],jules[bot]" trigger_phrase: "@claude" assignee_trigger: claude label_trigger: claude @@ -181,8 +179,6 @@ jobs: with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} - allowed_non_write_users: Copilot,copilot,jules[bot],jules - allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],copilot,github-actions,gemini[bot],claude[bot],jules[bot]" trigger_phrase: "@claude" assignee_trigger: claude label_trigger: claude diff --git a/.gitignore b/.gitignore index a718a8db6..7cfc3c4ac 100755 --- a/.gitignore +++ b/.gitignore @@ -229,5 +229,5 @@ test-results.xml mise.local.toml mise.local.env -.exportify/ -!.exportify/config.toml \ No newline at end of file +.gemini/ +gha-creds-*.json diff --git a/pyproject.toml b/pyproject.toml index 40c748465..1c4626edc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -120,7 +120,7 @@ dependencies = [ # So we pin it to make sure we don't break on minor releases "pydantic==2.12.5", # for, you know, platform dirs - "platformdirs>=4.9.4", + "platformdirs>=4.9.2", # psutil used for resource governance/limiting by engine "psutil>=7.2.2", "textcase>=0.4.5", @@ -140,20 +140,20 @@ dependencies = [ # for local providers (sentence-transformers, fastembed) to detect CPU/GPU features "py-cpuinfo>=9.0.0", # * ================ CLI Dependencies ==================* - "cyclopts>=4.10.0", - "rich>=14.3.3", + "cyclopts>=4.5.1", + "rich>=14.3.0", # * ================ Provider Clients ==================* # we must pin these to specific versions to ensure compatibility with our ClientOptions subclasses "boto3==1.42.19", - "cohere==5.20.7", + "cohere==5.20.1", "fastembed==0.7.4; python_version < '3.14'", "google-genai==1.56.0", # NOTE: We're waiting on pydantic-ai to update to 1.0+ before we can upgrade too - "huggingface-hub>=1.7.1", + "huggingface-hub==0.36.2", "mistralai==1.10.0", - "openai==2.28.0", - "qdrant-client==1.17.1", - "pydantic-ai-slim>=1.68.0", + "openai==2.17.0", + "qdrant-client==1.16.2", + "pydantic-ai-slim>=1.56.0", "sentence-transformers==5.2.0; python_version <= '3.14'", "voyageai==0.3.7", # * ================ Indexing and Engine ==================* @@ -171,12 +171,12 @@ dependencies = [ # fastmcp is the core MCP server framework "fastmcp>=2.14.5", # just used for types but we need them at runtime for Pydantic models - "mcp>=1.23.3", + "mcp>=1.19.0", # Runs the core admin/management server "uvicorn[standard]>=0.40.0", # * ================ Configuration and Settings ==================* # pydantic-settings with toml and yaml support for config files - "pydantic-settings[toml,yaml]>=2.13.1", # Pulls: tomli>=2.0.1, pyyaml>=6.0.1 + "pydantic-settings[toml,yaml]>=2.12.0", # Pulls: tomli>=2.0.1, pyyaml>=6.0.1 # For writing toml config files "tomli-w>=1.2.0", # * ================ Telemetry and Observability ==================* diff --git a/scripts/build/generate-mcp-server-json.py b/scripts/build/generate-mcp-server-json.py index c5ecc1128..ee7107cc2 100755 --- a/scripts/build/generate-mcp-server-json.py +++ b/scripts/build/generate-mcp-server-json.py @@ -25,9 +25,9 @@ ConfigLanguage, EnvFormat, Provider, - ProviderCategory, ProviderEnvVarInfo, ProviderEnvVars, + ProviderCategory, SemanticSearchLanguage, ) diff --git a/scripts/model_data/hf-models.json b/scripts/model_data/hf-models.json old mode 100644 new mode 100755 index 9165ca37e..fb51cfecf --- a/scripts/model_data/hf-models.json +++ b/scripts/model_data/hf-models.json @@ -213,7 +213,6 @@ ] } }, - "models": {}, "models": { "Alibaba-NLP/gte-modernbert-base": { "adapted_from": null, @@ -3925,6 +3924,4 @@ "opensearch-project/opensearch-neural-sparse-encoding-doc-v2-mini" ] } -{ - "models": {} - } \ No newline at end of file +} \ No newline at end of file diff --git a/scripts/model_data/hf-models.json.license b/scripts/model_data/hf-models.json.license old mode 100644 new mode 100755 diff --git a/scripts/model_data/mteb_to_codeweaver.py b/scripts/model_data/mteb_to_codeweaver.py old mode 100644 new mode 100755 index db6b2275e..f34eb8a27 --- a/scripts/model_data/mteb_to_codeweaver.py +++ b/scripts/model_data/mteb_to_codeweaver.py @@ -47,11 +47,10 @@ # make sure codeweaver is importable -sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).parent.parent)) -from codeweaver.providers.provider import Provider - -from codeweaver.providers.embedding.capabilities.types import PartialCapabilities +from codeweaver.core import Provider +from codeweaver.providers import PartialCapabilities # TODO: Finish refactor to use these inline constants and eliminate the hf-models.json @@ -100,13 +99,6 @@ Note: FastEmbed also has some aliases, but we handle those dynamically below. """ -KNOWN_ALIASES: dict[str, dict[ModelName, ModelName]] = {"ollama": OLLAMA_ALIASES} -"""A mapping of provider names to their HF name → provider alias mappings. - -Keys are provider name strings (e.g. "ollama") and values are dicts mapping HF model names -to the provider-specific alias. FastEmbed aliases are handled dynamically via get_fastembed_aliases(). -""" - KNOWN_SPARSE_MODELS = { Provider.FASTEMBED: [ "Qdrant/bm25", @@ -390,7 +382,13 @@ def attempt_to_get_version(name: str) -> str | int | float | None: type DataMap = dict[ModelName, SimplifiedModelMeta] -type ModelMap = dict[ModelMaker, dict[ModelName, tuple[HFModelProviders, ...]]] +type ModelMap = dict[ + ModelMaker, + dict[ + ModelName, + tuple[Annotated[HFModelProviders, BeforeValidator(lambda v: Provider.from_string(v))], ...], + ], +] """A mapping of model makers to their models and the providers that support each model.""" @@ -522,24 +520,29 @@ def load(cls) -> RootJson: return cls.model_validate_json(cls._json_path.read_text()) -if JSON_CACHE.exists(): +""" _ROOT = RootJson.load() DATA = _ROOT.models MODEL_MAP_DATA = _ROOT.model_map ALIAS_MAP_DATA = _ROOT.aliases + SPARSE_MODELS = _ROOT.sparse_models + FLATTENED_ALIASES = _ROOT.flattened_aliases else: - _ROOT = RootJson(models={}) DATA = {} MODEL_MAP_DATA = {} ALIAS_MAP_DATA = {} + SPARSE_MODELS = {} FLATTENED_ALIASES = {} +""" def mteb_to_capabilities(model: SimplifiedModelMeta) -> PartialCapabilities: """ Convert an MTEB model metadata dictionary to a PartialCapabilities object. """ + loader = getattr(model, "loader", {}) + loader = loader if isinstance(loader, dict) else {} caps = { "name": model["name"], "default_dimension": model.get("embed_dim"), diff --git a/scripts/model_data/secondary_providers.json b/scripts/model_data/secondary_providers.json old mode 100644 new mode 100755 diff --git a/scripts/model_data/secondary_providers.json.license b/scripts/model_data/secondary_providers.json.license old mode 100644 new mode 100755 diff --git a/src/codeweaver/core/di/container.py b/src/codeweaver/core/di/container.py index c35dc4373..4da279b66 100644 --- a/src/codeweaver/core/di/container.py +++ b/src/codeweaver/core/di/container.py @@ -562,8 +562,6 @@ async def resolve( if self._is_union_type(interface): instance = await self._resolve_union_interface(interface, cache_key, _resolution_stack) return cast(T, instance) - elif interface is type(None): - return cast(T, None) # 1. Check overrides first # We check overrides before tags and singletons because overrides diff --git a/src/codeweaver/core/statistics.py b/src/codeweaver/core/statistics.py index 731eba270..b7c188016 100644 --- a/src/codeweaver/core/statistics.py +++ b/src/codeweaver/core/statistics.py @@ -84,10 +84,7 @@ async def _check_profile(container: Container) -> bool | None: ): from codeweaver.providers.config.profiles import ProviderProfile - return ( - profile is ProviderProfile.RECOMMENDED_CLOUD - or profile is ProviderProfile.RECOMMENDED - ) + return profile in [ProviderProfile.RECOMMENDED_CLOUD, ProviderProfile.RECOMMENDED] return None diff --git a/src/codeweaver/core/utils/generation.py b/src/codeweaver/core/utils/generation.py index 3477d3c27..953c3eeb8 100644 --- a/src/codeweaver/core/utils/generation.py +++ b/src/codeweaver/core/utils/generation.py @@ -19,21 +19,9 @@ if sys.version_info < (3, 14): - try: - from uuid_extensions import uuid7 as uuid7_gen - except ImportError: - def uuid7_gen(*args, **kwargs) -> UUID7: - from pydantic import UUID7 - from uuid import uuid4 - return cast(UUID7, uuid4()) + from uuid_extensions import uuid7 as uuid7_gen else: - try: - from uuid import uuid7 as uuid7_gen - except ImportError: - def uuid7_gen(*args, **kwargs) -> UUID7: - from pydantic import UUID7 - from uuid import uuid4 - return cast(UUID7, uuid4()) + from uuid import uuid7 as uuid7_gen def uuid7() -> UUID7: @@ -56,16 +44,10 @@ def uuid7_as_timestamp( ) -> int | datetime.datetime | None: """Utility to extract the timestamp from a UUID7, optionally as a datetime.""" if sys.version_info < (3, 14): - try: - from uuid_extensions import time_ns, uuid_to_datetime - - return uuid_to_datetime(uuid) if as_datetime else time_ns(uuid) - except ImportError: - return datetime.datetime.now(datetime.UTC) if as_datetime else int(datetime.datetime.now(datetime.UTC).timestamp() * 1e9) - try: - from uuid import uuid7 - except ImportError: - return datetime.datetime.now(datetime.UTC) if as_datetime else int(datetime.datetime.now(datetime.UTC).timestamp() * 1e9) + from uuid_extensions import time_ns, uuid_to_datetime + + return uuid_to_datetime(uuid) if as_datetime else time_ns(uuid) + from uuid import uuid7 uuid = uuid7(uuid) if isinstance(uuid, str | int) else uuid return ( diff --git a/src/codeweaver/engine/chunker/delimiters/custom.py b/src/codeweaver/engine/chunker/delimiters/custom.py index 423bd2d3c..4884511e1 100644 --- a/src/codeweaver/engine/chunker/delimiters/custom.py +++ b/src/codeweaver/engine/chunker/delimiters/custom.py @@ -357,14 +357,12 @@ def generate_rst_character_ranges(character: str) -> list[str]: nestable=False, ) -HTML_BLOCK_TAGS = frozenset({"html", "body", "main", "section", "article"}) - HTML_TAGS_PATTERNS = [ DelimiterPattern( starts=[f"<{tag}"], ends=[f""], kind=DelimiterKind.BLOCK - if tag in HTML_BLOCK_TAGS + if tag in ["html", "body", "main", "section", "article"] else DelimiterKind.PARAGRAPH, inclusive=True, take_whole_lines=True, diff --git a/src/codeweaver/providers/config/clients/multi.py b/src/codeweaver/providers/config/clients/multi.py index 35c15ab19..09074c4b7 100644 --- a/src/codeweaver/providers/config/clients/multi.py +++ b/src/codeweaver/providers/config/clients/multi.py @@ -49,20 +49,14 @@ GoogleCredentials = Any if has_package("fastembed") is not None or has_package("fastembed_gpu") is not None: - try: - from fastembed.common.types import OnnxProvider - except ImportError: - OnnxProvider = Any # type: ignore[assignment, misc] + from fastembed.common.types import OnnxProvider else: - OnnxProvider = Any # type: ignore[assignment, misc] + OnnxProvider = object if has_package("torch") is not None: - try: - from torch.nn import Module - except ImportError: - Module = Any # type: ignore[assignment, misc] + from torch.nn import Module else: - Module = Any # type: ignore[assignment, misc] + Module = object if has_package("sentence_transformers") is not None: # SentenceTransformerModelCardData contains these forward references: # - eval_results_dict: dict[SentenceEvaluator, dict[str, Any]] | None @@ -240,10 +234,7 @@ class FastEmbedClientOptions(ClientOptions): model_name: str cache_dir: str | None = None threads: int | None = None - onnx_providers: Annotated[ - Sequence[OnnxProvider] | None, - Field(alias="providers", serialization_alias="providers"), - ] = None + providers: Sequence[OnnxProvider] | None = None cuda: bool | None = None device_ids: list[int] | None = None lazy_load: bool = True @@ -254,10 +245,10 @@ def _resolve_device_settings(self) -> Self: from codeweaver.core import effective_cpu_count cpu_count = effective_cpu_count() - updates: dict[str, Any] = {"threads": self.threads or cpu_count} + object.__setattr__(self, "threads", self.threads or cpu_count) if self.cuda is False: - updates["device_ids"] = [] - return self.model_copy(update=updates) + object.__setattr__(self, "device_ids", []) + return self from codeweaver.providers.optimize import decide_fastembed_runtime decision = decide_fastembed_runtime( @@ -272,11 +263,11 @@ def _resolve_device_settings(self) -> Self: else: cuda = False device_ids = [] - updates["cuda"] = cuda - updates["device_ids"] = device_ids - if cuda and (not self.onnx_providers or ONNX_CUDA_PROVIDER not in self.onnx_providers): - updates["onnx_providers"] = [ONNX_CUDA_PROVIDER, *(self.onnx_providers or [])] - return self.model_copy(update=updates) + object.__setattr__(self, "cuda", cuda) + object.__setattr__(self, "device_ids", device_ids) + if cuda and (not self.providers or ONNX_CUDA_PROVIDER not in self.providers): + object.__setattr__(self, "providers", [ONNX_CUDA_PROVIDER, *(self.providers or [])]) + return self def _telemetry_keys(self) -> dict[FilteredKeyT, AnonymityConversion]: return {FilteredKey("cache_dir"): AnonymityConversion.HASH} diff --git a/src/codeweaver/providers/config/profiles.py b/src/codeweaver/providers/config/profiles.py index 5d658f0fb..2570f1974 100644 --- a/src/codeweaver/providers/config/profiles.py +++ b/src/codeweaver/providers/config/profiles.py @@ -268,9 +268,7 @@ def _recommended_default( ), data=(TavilyProviderSettings(provider=Provider.TAVILY),) if Provider.TAVILY.has_env_auth and has_package("tavily") - else (DuckDuckGoProviderSettings(provider=Provider.DUCKDUCKGO),) - if has_package("ddgs") - else (), + else (DuckDuckGoProviderSettings(provider=Provider.DUCKDUCKGO),), vector_store=( QdrantVectorStoreProviderSettings( provider=Provider.QDRANT, diff --git a/src/codeweaver/providers/reranking/providers/base.py b/src/codeweaver/providers/reranking/providers/base.py index 28e7a93b2..10143ca22 100644 --- a/src/codeweaver/providers/reranking/providers/base.py +++ b/src/codeweaver/providers/reranking/providers/base.py @@ -462,7 +462,7 @@ def _process_results( Note: This sync method is only called from async contexts (from the rerank method). """ # voyage and cohere return token count, others do not - if self.provider not in (Provider.VOYAGE, Provider.COHERE): + if self.provider not in [Provider.VOYAGE, Provider.COHERE]: # We're always called from async context (rerank method), so we can safely get the loop try: loop = loop or asyncio.get_running_loop() diff --git a/src/codeweaver/server/agent_api/search/__init__.py b/src/codeweaver/server/agent_api/search/__init__.py index 2bc16f378..44aab4843 100644 --- a/src/codeweaver/server/agent_api/search/__init__.py +++ b/src/codeweaver/server/agent_api/search/__init__.py @@ -177,12 +177,7 @@ async def _resolve_indexer_from_container() -> IndexingService | None: container = get_container() return await container.resolve(IndexingService) - except Exception as e: - logger.warning( - "Failed to resolve IndexingService from container: %s", - e, - exc_info=True, - ) + except Exception: return None @@ -205,7 +200,7 @@ async def _ensure_index_ready( # We enable reconciliation by default to fix any partial indexes await indexer.index_project(add_dense=True, add_sparse=True) except Exception as e: - logger.warning("Auto-indexing failed: %s", e, exc_info=True) + logger.warning("Auto-indexing failed: %s", e) async def _build_search_package(package: SearchPackageDep) -> SearchPackage: diff --git a/src/codeweaver/server/lifespan.py b/src/codeweaver/server/lifespan.py index 0d0b21d50..1042e0caf 100644 --- a/src/codeweaver/server/lifespan.py +++ b/src/codeweaver/server/lifespan.py @@ -199,4 +199,8 @@ async def http_lifespan( yield background_state +# Backward compatibility alias (deprecated) +combined_lifespan = http_lifespan + + __all__ = ("background_services_lifespan", "http_lifespan") diff --git a/tests/integration/chunker/config/test_client_factory_integration.py b/tests/integration/chunker/config/test_client_factory_integration.py index 31af96654..af73676fb 100644 --- a/tests/integration/chunker/config/test_client_factory_integration.py +++ b/tests/integration/chunker/config/test_client_factory_integration.py @@ -17,16 +17,6 @@ from codeweaver.core import Provider, ProviderCategory -def make_lazy_provider_mock(name: str, resolved_class: Mock, instance: Mock | None = None) -> Mock: - """Helper to create and configure a lazy provider mock.""" - lazy_mock = Mock() - lazy_mock.__name__ = name - lazy_mock._resolve.return_value = resolved_class - # mock_provider_lazy is invoked like the provider class - lazy_mock.return_value = instance if instance is not None else Mock() - return lazy_mock - - pytestmark = [ pytest.mark.integration, pytest.mark.skip(reason="ProviderRegistry removed - functionality tested through DI container"), @@ -85,8 +75,13 @@ def test_create_provider_with_client_from_map(self, registry): mock_provider_class = Mock() mock_provider_instance = Mock() - mock_provider_lazy = make_lazy_provider_mock( - "MockVoyageProvider", mock_provider_class, mock_provider_instance + mock_provider_lazy = Mock() + mock_provider_lazy.__name__ = ( + "MockVoyageProvider" # Fix: Add __name__ to lazy mock (not resolved class) + ) + mock_provider_lazy._resolve.return_value = mock_provider_class + mock_provider_lazy.return_value = ( + mock_provider_instance # Fix: mock_provider_lazy is called at line 959 ) mock_provider_class.return_value = mock_provider_instance @@ -129,7 +124,12 @@ def test_create_provider_skips_client_if_provided(self, registry): mock_lateimport._resolve.return_value = mock_client_class mock_provider_class = Mock() - mock_provider_lazy = make_lazy_provider_mock("MockVoyageProvider", mock_provider_class) + mock_provider_lazy = Mock() + mock_provider_lazy.__name__ = ( + "MockVoyageProvider" # Fix: Add __name__ to lazy mock (not resolved class) + ) + mock_provider_lazy._resolve.return_value = mock_provider_class + mock_provider_lazy.return_value = Mock() # Fix: mock_provider_lazy is called at line 959 mock_client_map = { Provider.VOYAGE: ( @@ -168,7 +168,12 @@ def test_create_provider_handles_client_creation_failure(self, registry): mock_lateimport._resolve.return_value = mock_client_class mock_provider_class = Mock(return_value=Mock()) - mock_provider_lazy = make_lazy_provider_mock("MockVoyageProvider", mock_provider_class) + mock_provider_lazy = Mock() + mock_provider_lazy.__name__ = ( + "MockVoyageProvider" # Fix: Add __name__ to lazy mock (not resolved class) + ) + mock_provider_lazy._resolve.return_value = mock_provider_class + mock_provider_lazy.return_value = Mock() # Fix: mock_provider_lazy is called at line 959 mock_client_map = { Provider.VOYAGE: ( @@ -241,7 +246,9 @@ def test_qdrant_provider_with_memory_mode(self, registry): mock_lateimport._resolve.return_value = mock_client_class mock_provider_class = Mock(return_value=Mock()) - mock_provider_lazy = make_lazy_provider_mock("MockQdrantProvider", mock_provider_class) + mock_provider_lazy = Mock() + mock_provider_lazy._resolve.return_value = mock_provider_class + mock_provider_lazy.return_value = Mock() # Fix: mock_provider_lazy is what gets called mock_client_map = { Provider.QDRANT: ( @@ -281,7 +288,8 @@ def test_qdrant_provider_with_url_mode(self, registry): mock_lateimport._resolve.return_value = mock_client_class mock_provider_class = Mock(return_value=Mock()) - mock_provider_lazy = make_lazy_provider_mock("MockQdrantProvider", mock_provider_class) + mock_provider_lazy = Mock() + mock_provider_lazy._resolve.return_value = mock_provider_class mock_client_map = { Provider.QDRANT: ( @@ -375,7 +383,12 @@ def test_string_provider_category_in_create_provider(self, registry): mock_lateimport._resolve.return_value = mock_client_class mock_provider_class = Mock(return_value=Mock()) - mock_provider_lazy = make_lazy_provider_mock("MockVoyageProvider", mock_provider_class) + mock_provider_lazy = Mock() + mock_provider_lazy.__name__ = ( + "MockVoyageProvider" # Fix: Add __name__ to lazy mock (not resolved class) + ) + mock_provider_lazy._resolve.return_value = mock_provider_class + mock_provider_lazy.return_value = Mock() # Fix: mock_provider_lazy is called at line 959 mock_client_map = { Provider.VOYAGE: ( diff --git a/tests/integration/providers/env_registry/test_definitions.py b/tests/integration/providers/env_registry/test_definitions.py index f67a5f9ff..5d71062d3 100644 --- a/tests/integration/providers/env_registry/test_definitions.py +++ b/tests/integration/providers/env_registry/test_definitions.py @@ -29,7 +29,6 @@ from codeweaver.providers.env_registry.registry import ProviderEnvRegistry -@pytest.mark.integration class TestOpenAIProvider: """Test OPENAI base provider configuration.""" @@ -86,7 +85,6 @@ def test_openai_no_inheritance(self) -> None: assert OPENAI.inherits_from is None -@pytest.mark.integration class TestDeepSeekProvider: """Test DEEPSEEK provider configuration.""" @@ -113,7 +111,6 @@ def test_deepseek_note(self) -> None: assert "DeepSeek" in DEEPSEEK.note -@pytest.mark.integration class TestFireworksProvider: """Test FIREWORKS provider configuration.""" @@ -140,7 +137,6 @@ def test_fireworks_inheritance(self) -> None: assert FIREWORKS.inherits_from == "openai" -@pytest.mark.integration class TestTogetherProvider: """Test TOGETHER provider configuration.""" @@ -166,7 +162,6 @@ def test_together_note(self) -> None: assert "Together" in TOGETHER.note -@pytest.mark.integration class TestCerebrasProvider: """Test CEREBRAS provider configuration.""" @@ -192,7 +187,6 @@ def test_cerebras_inheritance(self) -> None: assert CEREBRAS.inherits_from == "openai" -@pytest.mark.integration class TestMoonshotProvider: """Test MOONSHOT provider configuration.""" @@ -213,7 +207,6 @@ def test_moonshot_inheritance(self) -> None: assert MOONSHOT.inherits_from == "openai" -@pytest.mark.integration class TestMorphProvider: """Test MORPH provider configuration.""" @@ -240,7 +233,6 @@ def test_morph_inheritance(self) -> None: assert MORPH.inherits_from == "openai" -@pytest.mark.integration class TestNebiusProvider: """Test NEBIUS provider configuration.""" @@ -266,7 +258,6 @@ def test_nebius_inheritance(self) -> None: assert NEBIUS.inherits_from == "openai" -@pytest.mark.integration class TestOpenRouterProvider: """Test OPENROUTER provider configuration.""" @@ -287,7 +278,6 @@ def test_openrouter_inheritance(self) -> None: assert OPENROUTER.inherits_from == "openai" -@pytest.mark.integration class TestOVHCloudProvider: """Test OVHCLOUD provider configuration.""" @@ -313,7 +303,6 @@ def test_ovhcloud_inheritance(self) -> None: assert OVHCLOUD.inherits_from == "openai" -@pytest.mark.integration class TestSambaNovaProvider: """Test SAMBANOVA provider configuration.""" @@ -339,7 +328,6 @@ def test_sambanova_inheritance(self) -> None: assert SAMBANOVA.inherits_from == "openai" -@pytest.mark.integration class TestGroqProvider: """Test GROQ provider configuration.""" @@ -369,7 +357,6 @@ def test_groq_inheritance(self) -> None: assert GROQ.inherits_from == "openai" -@pytest.mark.integration class TestRegistryAutoDiscovery: """Test registry auto-discovery of provider definitions.""" @@ -423,7 +410,6 @@ def test_registry_all_providers(self) -> None: assert provider in all_providers, f"Provider {provider} not found in registry" -@pytest.mark.integration class TestInheritanceResolution: """Test inheritance resolution in registry.""" @@ -463,7 +449,6 @@ def test_together_inherits_openai_vars(self) -> None: assert "TOGETHER_API_KEY" in api_key_envs -@pytest.mark.integration class TestBoilerplateReduction: """Test that builder pattern reduces boilerplate vs manual definition.""" @@ -502,7 +487,6 @@ def test_all_providers_use_openai_client(self) -> None: assert "groq" in GROQ.clients -@pytest.mark.integration class TestPhase3Summary: """Test Phase 3 implementation summary and metrics.""" diff --git a/tests/integration/server/test_error_recovery.py b/tests/integration/server/test_error_recovery.py index d358d0712..4d630d8a5 100644 --- a/tests/integration/server/test_error_recovery.py +++ b/tests/integration/server/test_error_recovery.py @@ -37,7 +37,7 @@ def create_failing_provider_mock() -> MagicMock: mock_provider.name = Provider.OPENAI # Set name property mock_provider.embed_query = AsyncMock(side_effect=ConnectionError("Simulated API failure")) mock_provider.embed_documents = AsyncMock(side_effect=ConnectionError("Simulated API failure")) - mock_provider.circuit_breaker_state = CircuitBreakerState.CLOSED.variable + mock_provider.circuit_breaker_state = CircuitBreakerState.CLOSED.value mock_provider._circuit_state = CircuitBreakerState.CLOSED mock_provider._failure_count = 0 mock_provider._last_failure_time = None @@ -67,7 +67,7 @@ async def mock_embed_documents(*args, **kwargs): mock_provider = MagicMock(spec=EmbeddingProvider) mock_provider.embed_query = AsyncMock(side_effect=mock_embed_query) mock_provider.embed_documents = AsyncMock(side_effect=mock_embed_documents) - mock_provider.circuit_breaker_state = CircuitBreakerState.CLOSED.variable + mock_provider.circuit_breaker_state = CircuitBreakerState.CLOSED.value mock_provider._circuit_state = CircuitBreakerState.CLOSED mock_provider._failure_count = 0 mock_provider._last_failure_time = None @@ -100,7 +100,7 @@ async def mock_embed_documents(*args, **kwargs): mock_provider = MagicMock(spec=EmbeddingProvider) mock_provider.embed_query = AsyncMock(side_effect=mock_embed_query) mock_provider.embed_documents = AsyncMock(side_effect=mock_embed_documents) - mock_provider.circuit_breaker_state = CircuitBreakerState.CLOSED.variable + mock_provider.circuit_breaker_state = CircuitBreakerState.CLOSED.value mock_provider._circuit_state = CircuitBreakerState.CLOSED mock_provider._failure_count = 0 mock_provider._last_failure_time = None @@ -261,7 +261,7 @@ async def simulate_circuit_breaker(): provider._last_failure_time = time.time() if provider._failure_count >= 3: provider._circuit_state = CircuitBreakerState.OPEN - provider.circuit_breaker_state = CircuitBreakerState.OPEN.variable + provider.circuit_breaker_state = CircuitBreakerState.OPEN.value assert provider._failure_count == 3 assert provider._circuit_state == CircuitBreakerState.OPEN @@ -297,7 +297,7 @@ async def simulate_half_open_transition(): provider._last_failure_time = time.time() if provider._failure_count >= 3: provider._circuit_state = CircuitBreakerState.OPEN - provider.circuit_breaker_state = CircuitBreakerState.OPEN.variable + provider.circuit_breaker_state = CircuitBreakerState.OPEN.value assert provider._circuit_state == CircuitBreakerState.OPEN @@ -306,7 +306,7 @@ async def simulate_half_open_transition(): # Transition to half-open provider._circuit_state = CircuitBreakerState.HALF_OPEN - provider.circuit_breaker_state = CircuitBreakerState.HALF_OPEN.variable + provider.circuit_breaker_state = CircuitBreakerState.HALF_OPEN.value # Next request should succeed and close circuit result = await provider.embed_query("test_half_open") @@ -314,7 +314,7 @@ async def simulate_half_open_transition(): # Success should close circuit provider._circuit_state = CircuitBreakerState.CLOSED - provider.circuit_breaker_state = CircuitBreakerState.CLOSED.variable + provider.circuit_breaker_state = CircuitBreakerState.CLOSED.value provider._failure_count = 0 provider._last_failure_time = None diff --git a/tests/integration/server/test_health_monitoring.py b/tests/integration/server/test_health_monitoring.py index c65b381e3..d9b0b6402 100644 --- a/tests/integration/server/test_health_monitoring.py +++ b/tests/integration/server/test_health_monitoring.py @@ -34,7 +34,6 @@ from codeweaver.core import FailoverStats, Identifier, SessionStatistics from codeweaver.engine import IndexingService, IndexingStats -from codeweaver.providers import CircuitBreakerState from codeweaver.server import ( HealthResponse, HealthService, @@ -109,7 +108,7 @@ def mock_providers(mocker) -> dict: embedding_instance.model_name = "voyage-code-3" embedding_instance.__class__.__name__ = "VoyageEmbeddingProvider" embedding_instance.circuit_breaker_state = mocker.MagicMock() - embedding_instance.circuit_breaker_state.variable = CircuitBreakerState.CLOSED.variable + embedding_instance.circuit_breaker_state.variable = "closed" # Mock sparse embedding provider sparse_instance = mocker.MagicMock() @@ -120,7 +119,7 @@ def mock_providers(mocker) -> dict: reranking_instance.model_name = "voyage-rerank-2.5" reranking_instance.__class__.__name__ = "VoyageRerankingProvider" reranking_instance.circuit_breaker_state = mocker.MagicMock() - reranking_instance.circuit_breaker_state.variable = CircuitBreakerState.CLOSED.variable + reranking_instance.circuit_breaker_state.variable = "closed" return { "embedding": (embedding_instance,), @@ -326,7 +325,8 @@ async def test_health_status_degraded(health_service: HealthService, mocker): """ # Mock embedding provider as down (circuit breaker open) embedding_instance = health_service._providers["embedding"][0] - embedding_instance.circuit_breaker_state.variable = CircuitBreakerState.OPEN.variable + # FIX: Use .variable instead of .value to match BaseEnum interface + embedding_instance.circuit_breaker_state.variable = "open" response = await health_service.get_health_response() @@ -429,14 +429,16 @@ async def test_health_circuit_breaker_exposure(health_service: HealthService, mo # Test half_open state embedding_instance = health_service._providers["embedding"][0] - embedding_instance.circuit_breaker_state.variable = CircuitBreakerState.HALF_OPEN.variable + # FIX: Use .variable instead of .value to match BaseEnum interface + embedding_instance.circuit_breaker_state.variable = "half_open" response2 = await health_service.get_health_response() assert response2.services.embedding_provider.circuit_breaker_state == "half_open" assert response2.services.embedding_provider.status == "up" # Test open state (service down) - embedding_instance.circuit_breaker_state.variable = CircuitBreakerState.OPEN.variable + # FIX: Use .variable instead of .value to match BaseEnum interface + embedding_instance.circuit_breaker_state.variable = "open" response3 = await health_service.get_health_response() assert response3.services.embedding_provider.circuit_breaker_state == "open" diff --git a/tests/unit/cli/test_httpx_lazy_import.py b/tests/unit/cli/test_httpx_lazy_import.py index 5e7fdc3af..c5544e6ea 100644 --- a/tests/unit/cli/test_httpx_lazy_import.py +++ b/tests/unit/cli/test_httpx_lazy_import.py @@ -27,10 +27,6 @@ @pytest.mark.unit -@pytest.mark.async_test -@pytest.mark.external_api -@pytest.mark.mock_only -@pytest.mark.qdrant class TestHttpxLateImport: """Tests for lazy import of httpx in CLI commands. diff --git a/tests/unit/config/test_versioned_profile.py b/tests/unit/config/test_versioned_profile.py index 06ebfc6c4..fd394306d 100644 --- a/tests/unit/config/test_versioned_profile.py +++ b/tests/unit/config/test_versioned_profile.py @@ -15,7 +15,6 @@ from codeweaver.providers.config.sdk import VoyageEmbeddingConfig -@pytest.mark.unit class TestVersionedProfile: """Test suite for VersionedProfile dataclass.""" @@ -210,7 +209,6 @@ def test_integration_with_current_version( assert VersionedProfile.is_compatible_with(__version__, __version__) -@pytest.mark.unit class TestVersionedProfileIntegrationWithCollectionMetadata: """Test integration between VersionedProfile and CollectionMetadata.""" diff --git a/tests/unit/core/telemetry/test_privacy.py b/tests/unit/core/telemetry/test_privacy.py index c309c7463..e467ea874 100644 --- a/tests/unit/core/telemetry/test_privacy.py +++ b/tests/unit/core/telemetry/test_privacy.py @@ -61,7 +61,6 @@ def _telemetry_handler(self, serialized_self: dict[str, Any], /) -> dict[str, An return {"special_value": "REDACTED", "extra_field": "injected"} -@pytest.mark.unit class TestTelemetryPrivacy: """Test suite for telemetry privacy serialization.""" diff --git a/tests/unit/core/test_discovery.py b/tests/unit/core/test_discovery.py index 53f36534a..e2bebea63 100644 --- a/tests/unit/core/test_discovery.py +++ b/tests/unit/core/test_discovery.py @@ -3,7 +3,7 @@ # # SPDX-License-Identifier: MIT OR Apache-2.0 -"""Unit tests for core discovery logic.""" +import logging from pathlib import Path from unittest.mock import patch @@ -11,78 +11,145 @@ import pytest from codeweaver.core.discovery import DiscoveredFile -from codeweaver.core.metadata import ExtCategory +from codeweaver.core.utils import get_blake_hash pytestmark = [pytest.mark.unit] - @pytest.fixture -def temp_project(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path: - """Fixture to provide a temporary project directory and set the environment variable.""" - project_dir = tmp_path / "project" - project_dir.mkdir() - monkeypatch.setenv("CODEWEAVER_PROJECT_PATH", str(project_dir)) - return project_dir - - -def test_absolute_path_when_path_is_absolute() -> None: - """Test absolute_path property when the file path is already absolute.""" - abs_path = Path("/tmp/some_absolute_file.txt").resolve() - df = DiscoveredFile( - path=abs_path, - ext_category=ExtCategory.from_file(abs_path), - project_path=Path("/tmp/project") - ) - result = df.absolute_path - assert result == abs_path - - -def test_absolute_path_when_path_is_relative_and_project_path_set() -> None: - """Test absolute_path property when the file path is relative and project_path is set.""" - rel_path = Path("src/main.py") - proj_path = Path("/home/user/project") - df = DiscoveredFile( - path=rel_path, - ext_category=ExtCategory.from_file(rel_path), - project_path=proj_path - ) - result = df.absolute_path - assert result == proj_path / rel_path - - -def test_absolute_path_when_project_path_is_none_success(temp_project: Path) -> None: - """Test absolute_path property when project_path is falsy and get_project_path succeeds.""" - rel_path = Path("src/main.py") - df = DiscoveredFile( - path=rel_path, - ext_category=ExtCategory.from_file(rel_path), - project_path=temp_project - ) - # The property checks `if self.project_path:`. We can fake this by setting it to empty. - object.__setattr__(df, "project_path", "") - - result = df.absolute_path - - # It should fall back to get_project_path() which is temp_project due to the fixture - assert result == temp_project / rel_path - - -@patch('codeweaver.core.utils.get_project_path') -def test_absolute_path_when_project_path_is_none_filenotfound(mock_get_project_path) -> None: - """Test absolute_path property when project_path is falsy and get_project_path raises FileNotFoundError.""" - mock_get_project_path.side_effect = FileNotFoundError() - - rel_path = Path("src/main.py") - df = DiscoveredFile( - path=rel_path, - ext_category=ExtCategory.from_file(rel_path), - project_path=Path("/tmp") - ) - # The property checks `if self.project_path:`. We can fake this by setting it to empty. - object.__setattr__(df, "project_path", "") - - result = df.absolute_path - - # It should catch FileNotFoundError and return self.path - assert result == rel_path +def temp_project(tmp_path: Path) -> Path: + """Provides a temporary directory representing a project root.""" + return tmp_path + +def test_from_path_with_matching_hash(temp_project: Path, caplog: pytest.LogCaptureFixture) -> None: + test_file = temp_project / "test.py" + test_content = b"print('hello')" + test_file.write_bytes(test_content) + + expected_hash = get_blake_hash(test_content) + + with caplog.at_level(logging.WARNING): + df = DiscoveredFile.from_path(test_file, file_hash=expected_hash, project_path=temp_project) + + assert df is not None + assert df.file_hash == expected_hash + assert "Provided file_hash does not match" not in caplog.text + +def test_from_path_with_mismatching_hash(temp_project: Path, caplog: pytest.LogCaptureFixture) -> None: + test_file = temp_project / "test.py" + test_content = b"print('hello')" + test_file.write_bytes(test_content) + + mismatch_hash = get_blake_hash(b"print('world')") + computed_hash = get_blake_hash(test_content) + + with caplog.at_level(logging.WARNING): + df = DiscoveredFile.from_path(test_file, file_hash=mismatch_hash, project_path=temp_project) + + assert df is not None + assert df.file_hash == computed_hash + assert "Provided file_hash does not match computed hash" in caplog.text + +def test_from_path_without_hash(temp_project: Path) -> None: + test_file = temp_project / "test.py" + test_content = b"print('hello')" + test_file.write_bytes(test_content) + + computed_hash = get_blake_hash(test_content) + + df = DiscoveredFile.from_path(test_file, project_path=temp_project) + + assert df is not None + assert df.file_hash == computed_hash + +def test_from_path_with_directory_resolves_git_branch(temp_project: Path) -> None: + test_dir = temp_project / "src" + test_dir.mkdir() + + with patch("codeweaver.core.discovery.get_git_branch", return_value="custom-branch") as mock_git: + df = DiscoveredFile.from_path(test_dir, project_path=temp_project) + + assert df is None # ExtCategory.from_file returns None for directories + mock_git.assert_called_once_with(test_dir) + +def test_from_path_with_file_resolves_git_branch(temp_project: Path) -> None: + test_file = temp_project / "test.py" + test_file.write_text("print('hello')") + + with patch("codeweaver.core.discovery.get_git_branch", return_value="custom-branch") as mock_git: + df = DiscoveredFile.from_path(test_file, project_path=temp_project) + + assert df is not None + assert df.git_branch == "custom-branch" + mock_git.assert_called_once_with(temp_project) + +def test_from_path_with_invalid_ext_category(temp_project: Path) -> None: + test_file = temp_project / "test.invalidext12345" + test_file.write_text("invalid") + + df = DiscoveredFile.from_path(test_file, project_path=temp_project) + + assert df is None + +def test_from_path_with_injected_project_path(temp_project: Path) -> None: + test_file = temp_project / "test.py" + test_file.write_text("print('hello')") + + with patch("codeweaver.core.utils.filesystem.get_project_path", return_value=temp_project): + from codeweaver.core.di import INJECTED + df = DiscoveredFile.from_path(test_file, project_path=INJECTED) + + assert df is not None + assert df.project_path == temp_project + +def test_from_path_when_read_bytes_raises_exception(temp_project: Path) -> None: + test_file = temp_project / "test.py" + test_file.write_text("print('hello')") + + with patch("pathlib.Path.read_bytes", side_effect=PermissionError("Access denied")): + with pytest.raises(PermissionError): + DiscoveredFile.from_path(test_file, project_path=temp_project) + +def test_from_path_with_symbolic_link(temp_project: Path) -> None: + target_file = temp_project / "target.py" + target_file.write_text("print('hello')") + + symlink_file = temp_project / "symlink.py" + symlink_file.symlink_to(target_file) + + df = DiscoveredFile.from_path(symlink_file, project_path=temp_project) + + assert df is not None + assert df.file_hash == get_blake_hash(b"print('hello')") + +def test_from_path_with_git_branch_failure(temp_project: Path) -> None: + test_file = temp_project / "test.py" + test_file.write_text("print('hello')") + + with patch("codeweaver.core.discovery.get_git_branch", side_effect=Exception("Git not found")): + with pytest.raises(Exception, match="Git not found"): + DiscoveredFile.from_path(test_file, project_path=temp_project) + +def test_absolute_path_with_absolute_path(temp_project: Path) -> None: + test_file = temp_project / "test.py" + test_file.write_text("print('hello')") + df = DiscoveredFile.from_path(test_file, project_path=temp_project) + assert df is not None + assert df.absolute_path == test_file + +def test_absolute_path_with_relative_path(temp_project: Path) -> None: + test_file = temp_project / "test.py" + test_file.write_text("print('hello')") + df = DiscoveredFile.from_path(test_file, project_path=temp_project) + assert df is not None + assert df.absolute_path == test_file + +def test_absolute_path_fallback(temp_project: Path) -> None: + test_file = temp_project / "test.py" + test_file.write_text("print('hello')") + df = DiscoveredFile.from_path(test_file, project_path=temp_project) + assert df is not None + + with patch("codeweaver.core.utils.filesystem.get_project_path", return_value=temp_project): + object.__setattr__(df, "project_path", None) + assert df.absolute_path == test_file diff --git a/uv.lock b/uv.lock index 71d2b4cf3..bf6adf77b 100644 --- a/uv.lock +++ b/uv.lock @@ -157,7 +157,7 @@ wheels = [ [[package]] name = "anthropic" -version = "0.84.0" +version = "0.79.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -169,9 +169,9 @@ dependencies = [ { name = "sniffio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/ea/0869d6df9ef83dcf393aeefc12dd81677d091c6ffc86f783e51cf44062f2/anthropic-0.84.0.tar.gz", hash = "sha256:72f5f90e5aebe62dca316cb013629cfa24996b0f5a4593b8c3d712bc03c43c37", size = 539457, upload-time = "2026-02-25T05:22:38.54Z" } +sdist = { url = "https://files.pythonhosted.org/packages/15/b1/91aea3f8fd180d01d133d931a167a78a3737b3fd39ccef2ae8d6619c24fd/anthropic-0.79.0.tar.gz", hash = "sha256:8707aafb3b1176ed6c13e2b1c9fb3efddce90d17aee5d8b83a86c70dcdcca871", size = 509825, upload-time = "2026-02-07T18:06:18.388Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/64/ca/218fa25002a332c0aa149ba18ffc0543175998b1f65de63f6d106689a345/anthropic-0.84.0-py3-none-any.whl", hash = "sha256:861c4c50f91ca45f942e091d83b60530ad6d4f98733bfe648065364da05d29e7", size = 455156, upload-time = "2026-02-25T05:22:40.468Z" }, + { url = "https://files.pythonhosted.org/packages/95/b2/cc0b8e874a18d7da50b0fda8c99e4ac123f23bf47b471827c5f6f3e4a767/anthropic-0.79.0-py3-none-any.whl", hash = "sha256:04cbd473b6bbda4ca2e41dd670fe2f829a911530f01697d0a1e37321eb75f3cf", size = 405918, upload-time = "2026-02-07T18:06:20.246Z" }, ] [[package]] @@ -878,8 +878,8 @@ requires-dist = [ { name = "boto3", specifier = "==1.42.19" }, { name = "code-weaver-daemon", editable = "packages/codeweaver-daemon" }, { name = "code-weaver-tokenizers", editable = "packages/codeweaver-tokenizers" }, - { name = "cohere", specifier = "==5.20.7" }, - { name = "cyclopts", specifier = ">=4.10.0" }, + { name = "cohere", specifier = "==5.20.1" }, + { name = "cyclopts", specifier = ">=4.5.1" }, { name = "ddgs", marker = "extra == 'full'" }, { name = "ddgs", marker = "extra == 'full-gpu'" }, { name = "ddgs", marker = "extra == 'recommended'" }, @@ -899,16 +899,16 @@ requires-dist = [ { name = "fastembed-gpu", marker = "python_full_version < '3.14' and extra == 'gpu-support'" }, { name = "fastmcp", specifier = ">=2.14.5" }, { name = "google-genai", specifier = "==1.56.0" }, - { name = "huggingface-hub", specifier = ">=1.7.1" }, + { name = "huggingface-hub", specifier = "==0.36.2" }, { name = "lateimport", specifier = ">=0.1.0" }, - { name = "mcp", specifier = ">=1.23.3" }, + { name = "mcp", specifier = ">=1.19.0" }, { name = "mistralai", specifier = "==1.10.0" }, { name = "numpy", specifier = ">=2.4.2" }, - { name = "openai", specifier = "==2.28.0" }, + { name = "openai", specifier = "==2.17.0" }, { name = "permit-fastmcp", marker = "extra == 'auth-permitio'" }, { name = "permit-fastmcp", marker = "extra == 'full'" }, { name = "permit-fastmcp", marker = "extra == 'full-gpu'" }, - { name = "platformdirs", specifier = ">=4.9.4" }, + { name = "platformdirs", specifier = ">=4.9.2" }, { name = "posthog", specifier = ">=7.8.2" }, { name = "psutil", specifier = ">=7.2.2" }, { name = "py-cpuinfo", specifier = ">=9.0.0" }, @@ -918,7 +918,7 @@ requires-dist = [ { name = "py-cpuinfo", marker = "extra == 'recommended-local-only'" }, { name = "py-cpuinfo", marker = "extra == 'sentence-transformers'" }, { name = "pydantic", specifier = "==2.12.5" }, - { name = "pydantic-ai-slim", specifier = ">=1.68.0" }, + { name = "pydantic-ai-slim", specifier = ">=1.56.0" }, { name = "pydantic-ai-slim", extras = ["anthropic"], marker = "extra == 'anthropic'" }, { name = "pydantic-ai-slim", extras = ["anthropic", "bedrock", "cohere", "google", "groq", "huggingface", "mistral", "openai", "retries", "xai"], marker = "extra == 'full'" }, { name = "pydantic-ai-slim", extras = ["anthropic", "bedrock", "cohere", "google", "groq", "huggingface", "mistral", "openai", "retries", "xai"], marker = "extra == 'full-gpu'" }, @@ -938,11 +938,11 @@ requires-dist = [ { name = "pydantic-settings", extras = ["aws-secrets-manager", "toml", "yaml"], marker = "extra == 'aws-secrets-manager'" }, { name = "pydantic-settings", extras = ["azure-key-vault", "toml", "yaml"], marker = "extra == 'azure-key-vault'" }, { name = "pydantic-settings", extras = ["gcp-secret-manager", "toml", "yaml"], marker = "extra == 'gcp-secret-manager'" }, - { name = "pydantic-settings", extras = ["toml", "yaml"], specifier = ">=2.13.1" }, - { name = "qdrant-client", specifier = "==1.17.1" }, + { name = "pydantic-settings", extras = ["toml", "yaml"], specifier = ">=2.12.0" }, + { name = "qdrant-client", specifier = "==1.16.2" }, { name = "qdrant-client", marker = "extra == 'in-memory'" }, { name = "qdrant-client", marker = "extra == 'qdrant'" }, - { name = "rich", specifier = ">=14.3.3" }, + { name = "rich", specifier = ">=14.3.0" }, { name = "rignore", specifier = ">=0.7.6" }, { name = "sentence-transformers", marker = "python_full_version < '3.15'", specifier = "==5.2.0" }, { name = "sentence-transformers", marker = "extra == 'full'" }, @@ -1067,7 +1067,7 @@ provides-extras = ["test"] [[package]] name = "cohere" -version = "5.20.7" +version = "5.20.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fastavro" }, @@ -1079,9 +1079,9 @@ dependencies = [ { name = "types-requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/44/0b/96e2b55a0114ed9d69b3154565f54b764e7530735426290b000f467f4c0f/cohere-5.20.7.tar.gz", hash = "sha256:997ed85fabb3a1e4a4c036fdb520382e7bfa670db48eb59a026803b6f7061dbb", size = 184986, upload-time = "2026-02-25T01:22:18.673Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/ed/bb02083654bdc089ae4ef1cd7691fd2233f1fd9f32bcbfacc80ff57d9775/cohere-5.20.1.tar.gz", hash = "sha256:50973f63d2c6138ff52ce37d8d6f78ccc539af4e8c43865e960d68e0bf835b6f", size = 180820, upload-time = "2025-12-18T16:39:50.975Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9d/86/dc991a75e3b9c2007b90dbfaf7f36fdb2457c216f799e26ce0474faf0c1f/cohere-5.20.7-py3-none-any.whl", hash = "sha256:043fef2a12c30c07e9b2c1f0b869fd66ffd911f58d1492f87e901c4190a65914", size = 323389, upload-time = "2026-02-25T01:22:16.902Z" }, + { url = "https://files.pythonhosted.org/packages/7a/e3/94eb11ac3ebaaa3a6afb5d2ff23db95d58bc468ae538c388edf49f2f20b5/cohere-5.20.1-py3-none-any.whl", hash = "sha256:d230fd13d95ba92ae927fce3dd497599b169883afc7954fe29b39fb8d5df5fc7", size = 318973, upload-time = "2025-12-18T16:39:49.504Z" }, ] [[package]] @@ -1552,7 +1552,7 @@ wheels = [ [[package]] name = "fastembed-gpu" -version = "0.7.4" +version = "0.7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub", marker = "(python_full_version < '3.14' and extra == 'extra-11-code-weaver-full-gpu') or (python_full_version < '3.14' and extra != 'extra-11-code-weaver-full' and extra == 'extra-11-code-weaver-gpu-support') or (python_full_version < '3.14' and extra != 'extra-11-code-weaver-gpu-support' and extra == 'project-13-fastembed-gpu') or (python_full_version < '3.14' and extra != 'extra-11-code-weaver-full' and extra != 'project-13-fastembed-gpu' and extra != 'project-9-fastembed') or (extra == 'extra-11-code-weaver-full' and extra == 'extra-11-code-weaver-full-gpu') or (extra == 'extra-11-code-weaver-full' and extra == 'project-13-fastembed-gpu') or (extra == 'extra-11-code-weaver-full-gpu' and extra == 'project-9-fastembed') or (extra == 'extra-11-code-weaver-gpu-support' and extra == 'project-9-fastembed') or (extra == 'project-13-fastembed-gpu' and extra == 'project-9-fastembed')" }, @@ -1566,9 +1566,9 @@ dependencies = [ { name = "tokenizers", marker = "(python_full_version < '3.14' and extra == 'extra-11-code-weaver-full-gpu') or (python_full_version < '3.14' and extra != 'extra-11-code-weaver-full' and extra == 'extra-11-code-weaver-gpu-support') or (python_full_version < '3.14' and extra != 'extra-11-code-weaver-gpu-support' and extra == 'project-13-fastembed-gpu') or (python_full_version < '3.14' and extra != 'extra-11-code-weaver-full' and extra != 'project-13-fastembed-gpu' and extra != 'project-9-fastembed') or (extra == 'extra-11-code-weaver-full' and extra == 'extra-11-code-weaver-full-gpu') or (extra == 'extra-11-code-weaver-full' and extra == 'project-13-fastembed-gpu') or (extra == 'extra-11-code-weaver-full-gpu' and extra == 'project-9-fastembed') or (extra == 'extra-11-code-weaver-gpu-support' and extra == 'project-9-fastembed') or (extra == 'project-13-fastembed-gpu' and extra == 'project-9-fastembed')" }, { name = "tqdm", marker = "(python_full_version < '3.14' and extra == 'extra-11-code-weaver-full-gpu') or (python_full_version < '3.14' and extra != 'extra-11-code-weaver-full' and extra == 'extra-11-code-weaver-gpu-support') or (python_full_version < '3.14' and extra != 'extra-11-code-weaver-gpu-support' and extra == 'project-13-fastembed-gpu') or (python_full_version < '3.14' and extra != 'extra-11-code-weaver-full' and extra != 'project-13-fastembed-gpu' and extra != 'project-9-fastembed') or (extra == 'extra-11-code-weaver-full' and extra == 'extra-11-code-weaver-full-gpu') or (extra == 'extra-11-code-weaver-full' and extra == 'project-13-fastembed-gpu') or (extra == 'extra-11-code-weaver-full-gpu' and extra == 'project-9-fastembed') or (extra == 'extra-11-code-weaver-gpu-support' and extra == 'project-9-fastembed') or (extra == 'project-13-fastembed-gpu' and extra == 'project-9-fastembed')" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fd/7e/5647b226baf7abe379e10ed46fb6de47a5838a96e50baa2be855510d792f/fastembed_gpu-0.7.4.tar.gz", hash = "sha256:f0a21792093b355a234685ad48cc16a25fbf091498cf114065ee62c05ada1a05", size = 68862, upload-time = "2025-12-05T12:08:43.517Z" } +sdist = { url = "https://files.pythonhosted.org/packages/de/b0/9d528c2dfc319d218a9829b9018e480cd23d620492636817321ad0fb5cce/fastembed_gpu-0.7.3.tar.gz", hash = "sha256:2ed106290677b4cc93e3a8467fd3fbcbf288c1e11fa02cebed67f02a7ccb2427", size = 66636, upload-time = "2025-08-29T11:20:05.13Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/c9/0aecd6914a3b4d7b3431c6d9e5cc7111dfb658cc32bb56e65e6add9e930c/fastembed_gpu-0.7.4-py3-none-any.whl", hash = "sha256:970881d22788165065fdb3873846304a27a5c8ff771c656fa7ff38b7a1d22274", size = 108539, upload-time = "2025-12-05T12:08:42.208Z" }, + { url = "https://files.pythonhosted.org/packages/48/2b/8b1788989dcf9394195a43b6b5ee1b19ed5e628f9aa3c92b46946bca5748/fastembed_gpu-0.7.3-py3-none-any.whl", hash = "sha256:762385f788b55d05ccbb663516d127194d6567426916a7d8fc63378ffcfcdc41", size = 105371, upload-time = "2025-08-29T11:20:03.707Z" }, ] [[package]] @@ -2017,34 +2017,31 @@ wheels = [ [[package]] name = "hf-xet" -version = "1.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/09/08/23c84a26716382c89151b5b447b4beb19e3345f3a93d3b73009a71a57ad3/hf_xet-1.4.2.tar.gz", hash = "sha256:b7457b6b482d9e0743bd116363239b1fa904a5e65deede350fbc0c4ea67c71ea", size = 672357, upload-time = "2026-03-13T06:58:51.077Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/06/e8cf74c3c48e5485c7acc5a990d0d8516cdfb5fdf80f799174f1287cc1b5/hf_xet-1.4.2-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:ac8202ae1e664b2c15cdfc7298cbb25e80301ae596d602ef7870099a126fcad4", size = 3796125, upload-time = "2026-03-13T06:58:33.177Z" }, - { url = "https://files.pythonhosted.org/packages/66/d4/b73ebab01cbf60777323b7de9ef05550790451eb5172a220d6b9845385ec/hf_xet-1.4.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6d2f8ee39fa9fba9af929f8c0d0482f8ee6e209179ad14a909b6ad78ffcb7c81", size = 3555985, upload-time = "2026-03-13T06:58:31.797Z" }, - { url = "https://files.pythonhosted.org/packages/ff/e7/ded6d1bd041c3f2bca9e913a0091adfe32371988e047dd3a68a2463c15a2/hf_xet-1.4.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4642a6cf249c09da8c1f87fe50b24b2a3450b235bf8adb55700b52f0ea6e2eb6", size = 4212085, upload-time = "2026-03-13T06:58:24.323Z" }, - { url = "https://files.pythonhosted.org/packages/97/c1/a0a44d1f98934f7bdf17f7a915b934f9fca44bb826628c553589900f6df8/hf_xet-1.4.2-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:769431385e746c92dc05492dde6f687d304584b89c33d79def8367ace06cb555", size = 3988266, upload-time = "2026-03-13T06:58:22.887Z" }, - { url = "https://files.pythonhosted.org/packages/7a/82/be713b439060e7d1f1d93543c8053d4ef2fe7e6922c5b31642eaa26f3c4b/hf_xet-1.4.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c9dd1c1bc4cc56168f81939b0e05b4c36dd2d28c13dc1364b17af89aa0082496", size = 4188513, upload-time = "2026-03-13T06:58:40.858Z" }, - { url = "https://files.pythonhosted.org/packages/21/a6/cbd4188b22abd80ebd0edbb2b3e87f2633e958983519980815fb8314eae5/hf_xet-1.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fca58a2ae4e6f6755cc971ac6fcdf777ea9284d7e540e350bb000813b9a3008d", size = 4428287, upload-time = "2026-03-13T06:58:42.601Z" }, - { url = "https://files.pythonhosted.org/packages/b2/4e/84e45b25e2e3e903ed3db68d7eafa96dae9a1d1f6d0e7fc85120347a852f/hf_xet-1.4.2-cp313-cp313t-win_amd64.whl", hash = "sha256:163aab46854ccae0ab6a786f8edecbbfbaa38fcaa0184db6feceebf7000c93c0", size = 3665574, upload-time = "2026-03-13T06:58:53.881Z" }, - { url = "https://files.pythonhosted.org/packages/ee/71/c5ac2b9a7ae39c14e91973035286e73911c31980fe44e7b1d03730c00adc/hf_xet-1.4.2-cp313-cp313t-win_arm64.whl", hash = "sha256:09b138422ecbe50fd0c84d4da5ff537d27d487d3607183cd10e3e53f05188e82", size = 3528760, upload-time = "2026-03-13T06:58:52.187Z" }, - { url = "https://files.pythonhosted.org/packages/1e/0f/fcd2504015eab26358d8f0f232a1aed6b8d363a011adef83fe130bff88f7/hf_xet-1.4.2-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:949dcf88b484bb9d9276ca83f6599e4aa03d493c08fc168c124ad10b2e6f75d7", size = 3796493, upload-time = "2026-03-13T06:58:39.267Z" }, - { url = "https://files.pythonhosted.org/packages/82/56/19c25105ff81731ca6d55a188b5de2aa99d7a2644c7aa9de1810d5d3b726/hf_xet-1.4.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:41659966020d59eb9559c57de2cde8128b706a26a64c60f0531fa2318f409418", size = 3555797, upload-time = "2026-03-13T06:58:37.546Z" }, - { url = "https://files.pythonhosted.org/packages/bf/e3/8933c073186849b5e06762aa89847991d913d10a95d1603eb7f2c3834086/hf_xet-1.4.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5c588e21d80010119458dd5d02a69093f0d115d84e3467efe71ffb2c67c19146", size = 4212127, upload-time = "2026-03-13T06:58:30.539Z" }, - { url = "https://files.pythonhosted.org/packages/eb/01/f89ebba4e369b4ed699dcb60d3152753870996f41c6d22d3d7cac01310e1/hf_xet-1.4.2-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:a296744d771a8621ad1d50c098d7ab975d599800dae6d48528ba3944e5001ba0", size = 3987788, upload-time = "2026-03-13T06:58:29.139Z" }, - { url = "https://files.pythonhosted.org/packages/84/4d/8a53e5ffbc2cc33bbf755382ac1552c6d9af13f623ed125fe67cc3e6772f/hf_xet-1.4.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f563f7efe49588b7d0629d18d36f46d1658fe7e08dce3fa3d6526e1c98315e2d", size = 4188315, upload-time = "2026-03-13T06:58:48.017Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b8/b7a1c1b5592254bd67050632ebbc1b42cc48588bf4757cb03c2ef87e704a/hf_xet-1.4.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5b2e0132c56d7ee1bf55bdb638c4b62e7106f6ac74f0b786fed499d5548c5570", size = 4428306, upload-time = "2026-03-13T06:58:49.502Z" }, - { url = "https://files.pythonhosted.org/packages/a0/0c/40779e45b20e11c7c5821a94135e0207080d6b3d76e7b78ccb413c6f839b/hf_xet-1.4.2-cp314-cp314t-win_amd64.whl", hash = "sha256:2f45c712c2fa1215713db10df6ac84b49d0e1c393465440e9cb1de73ecf7bbf6", size = 3665826, upload-time = "2026-03-13T06:58:59.88Z" }, - { url = "https://files.pythonhosted.org/packages/51/4c/e2688c8ad1760d7c30f7c429c79f35f825932581bc7c9ec811436d2f21a0/hf_xet-1.4.2-cp314-cp314t-win_arm64.whl", hash = "sha256:6d53df40616f7168abfccff100d232e9d460583b9d86fa4912c24845f192f2b8", size = 3529113, upload-time = "2026-03-13T06:58:58.491Z" }, - { url = "https://files.pythonhosted.org/packages/b4/86/b40b83a2ff03ef05c4478d2672b1fc2b9683ff870e2b25f4f3af240f2e7b/hf_xet-1.4.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:71f02d6e4cdd07f344f6844845d78518cc7186bd2bc52d37c3b73dc26a3b0bc5", size = 3800339, upload-time = "2026-03-13T06:58:36.245Z" }, - { url = "https://files.pythonhosted.org/packages/64/2e/af4475c32b4378b0e92a587adb1aa3ec53e3450fd3e5fe0372a874531c00/hf_xet-1.4.2-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:e9b38d876e94d4bdcf650778d6ebbaa791dd28de08db9736c43faff06ede1b5a", size = 3559664, upload-time = "2026-03-13T06:58:34.787Z" }, - { url = "https://files.pythonhosted.org/packages/3c/4c/781267da3188db679e601de18112021a5cb16506fe86b246e22c5401a9c4/hf_xet-1.4.2-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:77e8c180b7ef12d8a96739a4e1e558847002afe9ea63b6f6358b2271a8bdda1c", size = 4217422, upload-time = "2026-03-13T06:58:27.472Z" }, - { url = "https://files.pythonhosted.org/packages/68/47/d6cf4a39ecf6c7705f887a46f6ef5c8455b44ad9eb0d391aa7e8a2ff7fea/hf_xet-1.4.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c3b3c6a882016b94b6c210957502ff7877802d0dbda8ad142c8595db8b944271", size = 3992847, upload-time = "2026-03-13T06:58:25.989Z" }, - { url = "https://files.pythonhosted.org/packages/2d/ef/e80815061abff54697239803948abc665c6b1d237102c174f4f7a9a5ffc5/hf_xet-1.4.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9d9a634cc929cfbaf2e1a50c0e532ae8c78fa98618426769480c58501e8c8ac2", size = 4193843, upload-time = "2026-03-13T06:58:44.59Z" }, - { url = "https://files.pythonhosted.org/packages/54/75/07f6aa680575d9646c4167db6407c41340cbe2357f5654c4e72a1b01ca14/hf_xet-1.4.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6b0932eb8b10317ea78b7da6bab172b17be03bbcd7809383d8d5abd6a2233e04", size = 4432751, upload-time = "2026-03-13T06:58:46.533Z" }, - { url = "https://files.pythonhosted.org/packages/cd/71/193eabd7e7d4b903c4aa983a215509c6114915a5a237525ec562baddb868/hf_xet-1.4.2-cp37-abi3-win_amd64.whl", hash = "sha256:ad185719fb2e8ac26f88c8100562dbf9dbdcc3d9d2add00faa94b5f106aea53f", size = 3671149, upload-time = "2026-03-13T06:58:57.07Z" }, - { url = "https://files.pythonhosted.org/packages/b4/7e/ccf239da366b37ba7f0b36095450efae4a64980bdc7ec2f51354205fdf39/hf_xet-1.4.2-cp37-abi3-win_arm64.whl", hash = "sha256:32c012286b581f783653e718c1862aea5b9eb140631685bb0c5e7012c8719a87", size = 3533426, upload-time = "2026-03-13T06:58:55.46Z" }, +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload-time = "2025-10-24T19:04:32.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/a5/85ef910a0aa034a2abcfadc360ab5ac6f6bc4e9112349bd40ca97551cff0/hf_xet-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649", size = 2861870, upload-time = "2025-10-24T19:04:11.422Z" }, + { url = "https://files.pythonhosted.org/packages/ea/40/e2e0a7eb9a51fe8828ba2d47fe22a7e74914ea8a0db68a18c3aa7449c767/hf_xet-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813", size = 2717584, upload-time = "2025-10-24T19:04:09.586Z" }, + { url = "https://files.pythonhosted.org/packages/a5/7d/daf7f8bc4594fdd59a8a596f9e3886133fdc68e675292218a5e4c1b7e834/hf_xet-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc", size = 3315004, upload-time = "2025-10-24T19:04:00.314Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ba/45ea2f605fbf6d81c8b21e4d970b168b18a53515923010c312c06cd83164/hf_xet-1.2.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5", size = 3222636, upload-time = "2025-10-24T19:03:58.111Z" }, + { url = "https://files.pythonhosted.org/packages/4a/1d/04513e3cab8f29ab8c109d309ddd21a2705afab9d52f2ba1151e0c14f086/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f", size = 3408448, upload-time = "2025-10-24T19:04:20.951Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7c/60a2756d7feec7387db3a1176c632357632fbe7849fce576c5559d4520c7/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832", size = 3503401, upload-time = "2025-10-24T19:04:22.549Z" }, + { url = "https://files.pythonhosted.org/packages/4e/64/48fffbd67fb418ab07451e4ce641a70de1c40c10a13e25325e24858ebe5a/hf_xet-1.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382", size = 2900866, upload-time = "2025-10-24T19:04:33.461Z" }, + { url = "https://files.pythonhosted.org/packages/e2/51/f7e2caae42f80af886db414d4e9885fac959330509089f97cccb339c6b87/hf_xet-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e", size = 2861861, upload-time = "2025-10-24T19:04:19.01Z" }, + { url = "https://files.pythonhosted.org/packages/6e/1d/a641a88b69994f9371bd347f1dd35e5d1e2e2460a2e350c8d5165fc62005/hf_xet-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8", size = 2717699, upload-time = "2025-10-24T19:04:17.306Z" }, + { url = "https://files.pythonhosted.org/packages/df/e0/e5e9bba7d15f0318955f7ec3f4af13f92e773fbb368c0b8008a5acbcb12f/hf_xet-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0", size = 3314885, upload-time = "2025-10-24T19:04:07.642Z" }, + { url = "https://files.pythonhosted.org/packages/21/90/b7fe5ff6f2b7b8cbdf1bd56145f863c90a5807d9758a549bf3d916aa4dec/hf_xet-1.2.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090", size = 3221550, upload-time = "2025-10-24T19:04:05.55Z" }, + { url = "https://files.pythonhosted.org/packages/6f/cb/73f276f0a7ce46cc6a6ec7d6c7d61cbfe5f2e107123d9bbd0193c355f106/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a", size = 3408010, upload-time = "2025-10-24T19:04:28.598Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1e/d642a12caa78171f4be64f7cd9c40e3ca5279d055d0873188a58c0f5fbb9/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f", size = 3503264, upload-time = "2025-10-24T19:04:30.397Z" }, + { url = "https://files.pythonhosted.org/packages/17/b5/33764714923fa1ff922770f7ed18c2daae034d21ae6e10dbf4347c854154/hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc", size = 2901071, upload-time = "2025-10-24T19:04:37.463Z" }, + { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload-time = "2025-10-24T19:04:15.366Z" }, + { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload-time = "2025-10-24T19:04:13.695Z" }, + { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload-time = "2025-10-24T19:04:03.596Z" }, + { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload-time = "2025-10-24T19:04:01.949Z" }, + { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload-time = "2025-10-24T19:04:24.585Z" }, + { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload-time = "2025-10-24T19:04:26.927Z" }, + { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" }, ] [[package]] @@ -2136,22 +2133,26 @@ wheels = [ [[package]] name = "huggingface-hub" -version = "1.7.1" +version = "0.36.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, { name = "fsspec" }, - { name = "hf-xet", marker = "platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64' or (extra == 'extra-11-code-weaver-full' and extra == 'extra-11-code-weaver-full-gpu') or (extra == 'extra-11-code-weaver-full' and extra == 'project-13-fastembed-gpu') or (extra == 'extra-11-code-weaver-full-gpu' and extra == 'project-9-fastembed') or (extra == 'extra-11-code-weaver-gpu-support' and extra == 'project-9-fastembed') or (extra == 'project-13-fastembed-gpu' and extra == 'project-9-fastembed')" }, - { name = "httpx" }, + { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64' or (extra == 'extra-11-code-weaver-full' and extra == 'extra-11-code-weaver-full-gpu') or (extra == 'extra-11-code-weaver-full' and extra == 'project-13-fastembed-gpu') or (extra == 'extra-11-code-weaver-full-gpu' and extra == 'project-9-fastembed') or (extra == 'extra-11-code-weaver-gpu-support' and extra == 'project-9-fastembed') or (extra == 'project-13-fastembed-gpu' and extra == 'project-9-fastembed')" }, { name = "packaging" }, { name = "pyyaml" }, + { name = "requests" }, { name = "tqdm" }, - { name = "typer" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b4/a8/94ccc0aec97b996a3a68f3e1fa06a4bd7185dd02bf22bfba794a0ade8440/huggingface_hub-1.7.1.tar.gz", hash = "sha256:be38fe66e9b03c027ad755cb9e4b87ff0303c98acf515b5d579690beb0bf3048", size = 722097, upload-time = "2026-03-13T09:36:07.758Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/b7/8cb61d2eece5fb05a83271da168186721c450eb74e3c31f7ef3169fa475b/huggingface_hub-0.36.2.tar.gz", hash = "sha256:1934304d2fb224f8afa3b87007d58501acfda9215b334eed53072dd5e815ff7a", size = 649782, upload-time = "2026-02-06T09:24:13.098Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/75/ca21955d6117a394a482c7862ce96216239d0e3a53133ae8510727a8bcfa/huggingface_hub-1.7.1-py3-none-any.whl", hash = "sha256:38c6cce7419bbde8caac26a45ed22b0cea24152a8961565d70ec21f88752bfaa", size = 616308, upload-time = "2026-03-13T09:36:06.062Z" }, + { url = "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl", hash = "sha256:48f0c8eac16145dfce371e9d2d7772854a4f591bcb56c9cf548accf531d54270", size = 566395, upload-time = "2026-02-06T09:24:11.133Z" }, +] + +[package.optional-dependencies] +inference = [ + { name = "aiohttp" }, ] [[package]] @@ -3465,7 +3466,7 @@ wheels = [ [[package]] name = "openai" -version = "2.28.0" +version = "2.17.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -3477,9 +3478,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/56/87/eb0abb4ef88ddb95b3c13149384c4c288f584f3be17d6a4f63f8c3e3c226/openai-2.28.0.tar.gz", hash = "sha256:bb7fdff384d2a787fa82e8822d1dd3c02e8cf901d60f1df523b7da03cbb6d48d", size = 670334, upload-time = "2026-03-13T19:56:27.306Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9c/a2/677f22c4b487effb8a09439fb6134034b5f0a39ca27df8b95fac23a93720/openai-2.17.0.tar.gz", hash = "sha256:47224b74bd20f30c6b0a6a329505243cb2f26d5cf84d9f8d0825ff8b35e9c999", size = 631445, upload-time = "2026-02-05T16:27:40.953Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5a/df122348638885526e53140e9c6b0d844af7312682b3bde9587eebc28b47/openai-2.28.0-py3-none-any.whl", hash = "sha256:79aa5c45dba7fef84085701c235cf13ba88485e1ef4f8dfcedc44fc2a698fc1d", size = 1141218, upload-time = "2026-03-13T19:56:25.46Z" }, + { url = "https://files.pythonhosted.org/packages/44/97/284535aa75e6e84ab388248b5a323fc296b1f70530130dee37f7f4fbe856/openai-2.17.0-py3-none-any.whl", hash = "sha256:4f393fd886ca35e113aac7ff239bcd578b81d8f104f5aedc7d3693eb2af1d338", size = 1069524, upload-time = "2026-02-05T16:27:38.941Z" }, ] [[package]] @@ -3813,11 +3814,11 @@ wheels = [ [[package]] name = "platformdirs" -version = "4.9.4" +version = "4.9.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/19/56/8d4c30c8a1d07013911a8fdbd8f89440ef9f08d07a1b50ab8ca8be5a20f9/platformdirs-4.9.4.tar.gz", hash = "sha256:1ec356301b7dc906d83f371c8f487070e99d3ccf9e501686456394622a01a934", size = 28737, upload-time = "2026-03-05T18:34:13.271Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/04/fea538adf7dbbd6d186f551d595961e564a3b6715bdf276b477460858672/platformdirs-4.9.2.tar.gz", hash = "sha256:9a33809944b9db043ad67ca0db94b14bf452cc6aeaac46a88ea55b26e2e9d291", size = 28394, upload-time = "2026-02-16T03:56:10.574Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/63/d7/97f7e3a6abb67d8080dd406fd4df842c2be0efaf712d1c899c32a075027c/platformdirs-4.9.4-py3-none-any.whl", hash = "sha256:68a9a4619a666ea6439f2ff250c12a853cd1cbd5158d258bd824a7df6be2f868", size = 21216, upload-time = "2026-03-05T18:34:12.172Z" }, + { url = "https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd", size = 21168, upload-time = "2026-02-16T03:56:08.891Z" }, ] [[package]] @@ -4182,20 +4183,20 @@ email = [ [[package]] name = "pydantic-ai-slim" -version = "1.68.0" +version = "1.56.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "genai-prices" }, - { name = "griffelib" }, + { name = "griffe" }, { name = "httpx" }, { name = "opentelemetry-api" }, { name = "pydantic" }, { name = "pydantic-graph" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d4/00/3e48684694e424a8d05dc1538fe53322854b0290fbb494f0007db62cd243/pydantic_ai_slim-1.68.0.tar.gz", hash = "sha256:38edda1dbe20137326903d8a223a9f4901d62b0a70799842cae3c7d60b3bebd2", size = 436924, upload-time = "2026-03-13T03:39:08.572Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/5c/3a577825b9c1da8f287be7f2ee6fe9aab48bc8a80e65c8518052c589f51c/pydantic_ai_slim-1.56.0.tar.gz", hash = "sha256:9f9f9c56b1c735837880a515ae5661b465b40207b25f3a3434178098b2137f05", size = 415265, upload-time = "2026-02-06T01:13:23.58Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/46/14/4e850e54024b453ed905aa92b50b286ed9b096979e7d0896005be5e5b74c/pydantic_ai_slim-1.68.0-py3-none-any.whl", hash = "sha256:c3234c743ab256c7f26aecb2296428a55ae3db9f9ebb8d725941cae887e8e027", size = 567829, upload-time = "2026-03-13T03:39:00.91Z" }, + { url = "https://files.pythonhosted.org/packages/62/4b/34682036528eeb9aaf093c2073540ddf399ab37b99d282a69ca41356f1aa/pydantic_ai_slim-1.56.0-py3-none-any.whl", hash = "sha256:d657e4113485020500b23b7390b0066e2a0277edc7577eaad2290735ca5dd7d5", size = 542270, upload-time = "2026-02-06T01:13:14.918Z" }, ] [package.optional-dependencies] @@ -4218,7 +4219,7 @@ groq = [ { name = "groq" }, ] huggingface = [ - { name = "huggingface-hub" }, + { name = "huggingface-hub", extra = ["inference"] }, ] mistral = [ { name = "mistralai" }, @@ -4307,7 +4308,7 @@ wheels = [ [[package]] name = "pydantic-graph" -version = "1.68.0" +version = "1.56.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "httpx" }, @@ -4315,23 +4316,23 @@ dependencies = [ { name = "pydantic" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/08/75/de53b774d7b96adc7a75ddc4cac4dfaea25d5538b5004710fc1e9a74180c/pydantic_graph-1.68.0.tar.gz", hash = "sha256:fa48d15659e9514393f0596f62a0355783309e725deedb14d8f3e68fccf3974a", size = 58534, upload-time = "2026-03-13T03:39:10.896Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/03/f92881cdb12d6f43e60e9bfd602e41c95408f06e2324d3729f7a194e2bcd/pydantic_graph-1.56.0.tar.gz", hash = "sha256:5e22972dbb43dbc379ab9944252ff864019abf3c7d465dcdf572fc8aec9a44a1", size = 58460, upload-time = "2026-02-06T01:13:26.708Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/bf/cd45f1987468679e8d631d1c0e6014c4156815440a985389bd11aeb4465f/pydantic_graph-1.68.0-py3-none-any.whl", hash = "sha256:a563291109c3efb69fe7553f20b164651fe98680252e8f07a3cd9a1db2f8a879", size = 72350, upload-time = "2026-03-13T03:39:04.439Z" }, + { url = "https://files.pythonhosted.org/packages/08/07/8c823eb4d196137c123d4d67434e185901d3cbaea3b0c2b7667da84e72c1/pydantic_graph-1.56.0-py3-none-any.whl", hash = "sha256:ec3f0a1d6fcedd4eb9c59fef45079c2ee4d4185878d70dae26440a9c974c6bb3", size = 72346, upload-time = "2026-02-06T01:13:18.792Z" }, ] [[package]] name = "pydantic-settings" -version = "2.13.1" +version = "2.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/52/6d/fffca34caecc4a3f97bda81b2098da5e8ab7efc9a66e819074a11955d87e/pydantic_settings-2.13.1.tar.gz", hash = "sha256:b4c11847b15237fb0171e1462bf540e294affb9b86db4d9aa5c01730bdbe4025", size = 223826, upload-time = "2026-02-19T13:45:08.055Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl", hash = "sha256:d56fd801823dbeae7f0975e1f8c8e25c258eb75d278ea7abb5d9cebb01b56237", size = 58929, upload-time = "2026-02-19T13:45:06.034Z" }, + { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, ] [package.optional-dependencies] @@ -4670,7 +4671,7 @@ wheels = [ [[package]] name = "qdrant-client" -version = "1.17.1" +version = "1.16.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "grpcio" }, @@ -4681,9 +4682,9 @@ dependencies = [ { name = "pydantic" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/30/dd/f8a8261b83946af3cd65943c93c4f83e044f01184e8525404989d22a81a5/qdrant_client-1.17.1.tar.gz", hash = "sha256:22f990bbd63485ed97ba551a4c498181fcb723f71dcab5d6e4e43fe1050a2bc0", size = 344979, upload-time = "2026-03-13T17:13:44.678Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/7d/3cd10e26ae97b35cf856ca1dc67576e42414ae39502c51165bb36bb1dff8/qdrant_client-1.16.2.tar.gz", hash = "sha256:ca4ef5f9be7b5eadeec89a085d96d5c723585a391eb8b2be8192919ab63185f0", size = 331112, upload-time = "2025-12-12T10:58:30.866Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/68/69/77d1a971c4b933e8c79403e99bcbb790463da5e48333cc4fd5d412c63c98/qdrant_client-1.17.1-py3-none-any.whl", hash = "sha256:6cda4064adfeaf211c751f3fbc00edbbdb499850918c7aff4855a9a759d56cbd", size = 389947, upload-time = "2026-03-13T17:13:43.156Z" }, + { url = "https://files.pythonhosted.org/packages/08/13/8ce16f808297e16968269de44a14f4fef19b64d9766be1d6ba5ba78b579d/qdrant_client-1.16.2-py3-none-any.whl", hash = "sha256:442c7ef32ae0f005e88b5d3c0783c63d4912b97ae756eb5e052523be682f17d3", size = 377186, upload-time = "2025-12-12T10:58:29.282Z" }, ] [[package]] @@ -4839,15 +4840,15 @@ wheels = [ [[package]] name = "rich" -version = "14.3.3" +version = "14.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" } +sdist = { url = "https://files.pythonhosted.org/packages/74/99/a4cab2acbb884f80e558b0771e97e21e939c5dfb460f488d19df485e8298/rich-14.3.2.tar.gz", hash = "sha256:e712f11c1a562a11843306f5ed999475f09ac31ffb64281f73ab29ffdda8b3b8", size = 230143, upload-time = "2026-02-01T16:20:47.908Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" }, + { url = "https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl", hash = "sha256:08e67c3e90884651da3239ea668222d19bea7b589149d8014a21c633420dbb69", size = 309963, upload-time = "2026-02-01T16:20:46.078Z" }, ] [[package]] @@ -5587,22 +5588,23 @@ wheels = [ [[package]] name = "transformers" -version = "5.3.0" +version = "4.57.1" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "filelock" }, { name = "huggingface-hub" }, { name = "numpy" }, { name = "packaging" }, { name = "pyyaml" }, { name = "regex" }, + { name = "requests" }, { name = "safetensors" }, { name = "tokenizers" }, { name = "tqdm" }, - { name = "typer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/1a/70e830d53ecc96ce69cfa8de38f163712d2b43ac52fbd743f39f56025c31/transformers-5.3.0.tar.gz", hash = "sha256:009555b364029da9e2946d41f1c5de9f15e6b1df46b189b7293f33a161b9c557", size = 8830831, upload-time = "2026-03-04T17:41:46.119Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/68/a39307bcc4116a30b2106f2e689130a48de8bd8a1e635b5e1030e46fcd9e/transformers-4.57.1.tar.gz", hash = "sha256:f06c837959196c75039809636cd964b959f6604b75b8eeec6fdfc0440b89cc55", size = 10142511, upload-time = "2025-10-14T15:39:26.18Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/88/ae8320064e32679a5429a2c9ebbc05c2bf32cefb6e076f9b07f6d685a9b4/transformers-5.3.0-py3-none-any.whl", hash = "sha256:50ac8c89c3c7033444fb3f9f53138096b997ebb70d4b5e50a2e810bf12d3d29a", size = 10661827, upload-time = "2026-03-04T17:41:42.722Z" }, + { url = "https://files.pythonhosted.org/packages/71/d3/c16c3b3cf7655a67db1144da94b021c200ac1303f82428f2beef6c2e72bb/transformers-4.57.1-py3-none-any.whl", hash = "sha256:b10d05da8fa67dc41644dbbf9bc45a44cb86ae33da6f9295f5fbf5b7890bd267", size = 11990925, upload-time = "2025-10-14T15:39:23.085Z" }, ] [[package]]