diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 7b3543a2f..1dece1ec7 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 - allowed_bots: "github-actions[bot],copilot[bot],dependabot[bot],copilot,github-actions,gemini[bot],claude[bot]" + 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[bot] label_trigger: claude @@ -105,6 +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]" trigger_phrase: "@claude" assignee_trigger: claude label_trigger: claude @@ -140,6 +142,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]" trigger_phrase: "@claude" assignee_trigger: claude label_trigger: claude @@ -177,6 +181,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]" trigger_phrase: "@claude" assignee_trigger: claude label_trigger: claude diff --git a/.gitignore b/.gitignore index 7cfc3c4ac..a718a8db6 100755 --- a/.gitignore +++ b/.gitignore @@ -229,5 +229,5 @@ test-results.xml mise.local.toml mise.local.env -.gemini/ -gha-creds-*.json +.exportify/ +!.exportify/config.toml \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 1c4626edc..40c748465 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.2", + "platformdirs>=4.9.4", # 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.5.1", - "rich>=14.3.0", + "cyclopts>=4.10.0", + "rich>=14.3.3", # * ================ Provider Clients ==================* # we must pin these to specific versions to ensure compatibility with our ClientOptions subclasses "boto3==1.42.19", - "cohere==5.20.1", + "cohere==5.20.7", "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==0.36.2", + "huggingface-hub>=1.7.1", "mistralai==1.10.0", - "openai==2.17.0", - "qdrant-client==1.16.2", - "pydantic-ai-slim>=1.56.0", + "openai==2.28.0", + "qdrant-client==1.17.1", + "pydantic-ai-slim>=1.68.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.19.0", + "mcp>=1.23.3", # 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.12.0", # Pulls: tomli>=2.0.1, pyyaml>=6.0.1 + "pydantic-settings[toml,yaml]>=2.13.1", # 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 ee7107cc2..c5ecc1128 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 100755 new mode 100644 index fb51cfecf..9165ca37e --- a/scripts/model_data/hf-models.json +++ b/scripts/model_data/hf-models.json @@ -213,6 +213,7 @@ ] } }, + "models": {}, "models": { "Alibaba-NLP/gte-modernbert-base": { "adapted_from": null, @@ -3924,4 +3925,6 @@ "opensearch-project/opensearch-neural-sparse-encoding-doc-v2-mini" ] } -} \ No newline at end of file +{ + "models": {} + } \ 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 100755 new mode 100644 diff --git a/scripts/model_data/mteb_to_codeweaver.py b/scripts/model_data/mteb_to_codeweaver.py old mode 100755 new mode 100644 index f34eb8a27..db6b2275e --- a/scripts/model_data/mteb_to_codeweaver.py +++ b/scripts/model_data/mteb_to_codeweaver.py @@ -47,10 +47,11 @@ # make sure codeweaver is importable -sys.path.insert(0, str(Path(__file__).parent.parent)) +sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src")) -from codeweaver.core import Provider -from codeweaver.providers import PartialCapabilities +from codeweaver.providers.provider import Provider + +from codeweaver.providers.embedding.capabilities.types import PartialCapabilities # TODO: Finish refactor to use these inline constants and eliminate the hf-models.json @@ -99,6 +100,13 @@ 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", @@ -382,13 +390,7 @@ def attempt_to_get_version(name: str) -> str | int | float | None: type DataMap = dict[ModelName, SimplifiedModelMeta] -type ModelMap = dict[ - ModelMaker, - dict[ - ModelName, - tuple[Annotated[HFModelProviders, BeforeValidator(lambda v: Provider.from_string(v))], ...], - ], -] +type ModelMap = dict[ModelMaker, dict[ModelName, tuple[HFModelProviders, ...]]] """A mapping of model makers to their models and the providers that support each model.""" @@ -520,29 +522,24 @@ 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 100755 new mode 100644 diff --git a/scripts/model_data/secondary_providers.json.license b/scripts/model_data/secondary_providers.json.license old mode 100755 new mode 100644 diff --git a/src/codeweaver/core/di/container.py b/src/codeweaver/core/di/container.py index 4da279b66..c35dc4373 100644 --- a/src/codeweaver/core/di/container.py +++ b/src/codeweaver/core/di/container.py @@ -562,6 +562,8 @@ 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 b7c188016..731eba270 100644 --- a/src/codeweaver/core/statistics.py +++ b/src/codeweaver/core/statistics.py @@ -84,7 +84,10 @@ async def _check_profile(container: Container) -> bool | None: ): from codeweaver.providers.config.profiles import ProviderProfile - return profile in [ProviderProfile.RECOMMENDED_CLOUD, ProviderProfile.RECOMMENDED] + return ( + profile is ProviderProfile.RECOMMENDED_CLOUD + or profile is ProviderProfile.RECOMMENDED + ) return None diff --git a/src/codeweaver/core/utils/generation.py b/src/codeweaver/core/utils/generation.py index 953c3eeb8..3477d3c27 100644 --- a/src/codeweaver/core/utils/generation.py +++ b/src/codeweaver/core/utils/generation.py @@ -19,9 +19,21 @@ if sys.version_info < (3, 14): - from uuid_extensions import uuid7 as uuid7_gen + 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()) else: - from uuid import uuid7 as uuid7_gen + 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()) def uuid7() -> UUID7: @@ -44,10 +56,16 @@ 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): - 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 + 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) 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 4884511e1..423bd2d3c 100644 --- a/src/codeweaver/engine/chunker/delimiters/custom.py +++ b/src/codeweaver/engine/chunker/delimiters/custom.py @@ -357,12 +357,14 @@ 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", "body", "main", "section", "article"] + if tag in HTML_BLOCK_TAGS 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 09074c4b7..35c15ab19 100644 --- a/src/codeweaver/providers/config/clients/multi.py +++ b/src/codeweaver/providers/config/clients/multi.py @@ -49,14 +49,20 @@ GoogleCredentials = Any if has_package("fastembed") is not None or has_package("fastembed_gpu") is not None: - from fastembed.common.types import OnnxProvider + try: + from fastembed.common.types import OnnxProvider + except ImportError: + OnnxProvider = Any # type: ignore[assignment, misc] else: - OnnxProvider = object + OnnxProvider = Any # type: ignore[assignment, misc] if has_package("torch") is not None: - from torch.nn import Module + try: + from torch.nn import Module + except ImportError: + Module = Any # type: ignore[assignment, misc] else: - Module = object + Module = Any # type: ignore[assignment, misc] if has_package("sentence_transformers") is not None: # SentenceTransformerModelCardData contains these forward references: # - eval_results_dict: dict[SentenceEvaluator, dict[str, Any]] | None @@ -234,7 +240,10 @@ class FastEmbedClientOptions(ClientOptions): model_name: str cache_dir: str | None = None threads: int | None = None - providers: Sequence[OnnxProvider] | None = None + onnx_providers: Annotated[ + Sequence[OnnxProvider] | None, + Field(alias="providers", serialization_alias="providers"), + ] = None cuda: bool | None = None device_ids: list[int] | None = None lazy_load: bool = True @@ -245,10 +254,10 @@ def _resolve_device_settings(self) -> Self: from codeweaver.core import effective_cpu_count cpu_count = effective_cpu_count() - object.__setattr__(self, "threads", self.threads or cpu_count) + updates: dict[str, Any] = {"threads": self.threads or cpu_count} if self.cuda is False: - object.__setattr__(self, "device_ids", []) - return self + updates["device_ids"] = [] + return self.model_copy(update=updates) from codeweaver.providers.optimize import decide_fastembed_runtime decision = decide_fastembed_runtime( @@ -263,11 +272,11 @@ def _resolve_device_settings(self) -> Self: else: cuda = False device_ids = [] - 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 + 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) 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 2570f1974..5d658f0fb 100644 --- a/src/codeweaver/providers/config/profiles.py +++ b/src/codeweaver/providers/config/profiles.py @@ -268,7 +268,9 @@ def _recommended_default( ), data=(TavilyProviderSettings(provider=Provider.TAVILY),) if Provider.TAVILY.has_env_auth and has_package("tavily") - else (DuckDuckGoProviderSettings(provider=Provider.DUCKDUCKGO),), + else (DuckDuckGoProviderSettings(provider=Provider.DUCKDUCKGO),) + if has_package("ddgs") + else (), 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 10143ca22..28e7a93b2 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 44aab4843..2bc16f378 100644 --- a/src/codeweaver/server/agent_api/search/__init__.py +++ b/src/codeweaver/server/agent_api/search/__init__.py @@ -177,7 +177,12 @@ async def _resolve_indexer_from_container() -> IndexingService | None: container = get_container() return await container.resolve(IndexingService) - except Exception: + except Exception as e: + logger.warning( + "Failed to resolve IndexingService from container: %s", + e, + exc_info=True, + ) return None @@ -200,7 +205,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) + logger.warning("Auto-indexing failed: %s", e, exc_info=True) async def _build_search_package(package: SearchPackageDep) -> SearchPackage: diff --git a/src/codeweaver/server/lifespan.py b/src/codeweaver/server/lifespan.py index 1042e0caf..0d0b21d50 100644 --- a/src/codeweaver/server/lifespan.py +++ b/src/codeweaver/server/lifespan.py @@ -199,8 +199,4 @@ 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 af73676fb..31af96654 100644 --- a/tests/integration/chunker/config/test_client_factory_integration.py +++ b/tests/integration/chunker/config/test_client_factory_integration.py @@ -17,6 +17,16 @@ 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"), @@ -75,13 +85,8 @@ def test_create_provider_with_client_from_map(self, registry): mock_provider_class = Mock() mock_provider_instance = Mock() - 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_lazy = make_lazy_provider_mock( + "MockVoyageProvider", mock_provider_class, mock_provider_instance ) mock_provider_class.return_value = mock_provider_instance @@ -124,12 +129,7 @@ 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 = 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_provider_lazy = make_lazy_provider_mock("MockVoyageProvider", mock_provider_class) mock_client_map = { Provider.VOYAGE: ( @@ -168,12 +168,7 @@ 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 = 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_provider_lazy = make_lazy_provider_mock("MockVoyageProvider", mock_provider_class) mock_client_map = { Provider.VOYAGE: ( @@ -246,9 +241,7 @@ 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 = 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_provider_lazy = make_lazy_provider_mock("MockQdrantProvider", mock_provider_class) mock_client_map = { Provider.QDRANT: ( @@ -288,8 +281,7 @@ 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 = Mock() - mock_provider_lazy._resolve.return_value = mock_provider_class + mock_provider_lazy = make_lazy_provider_mock("MockQdrantProvider", mock_provider_class) mock_client_map = { Provider.QDRANT: ( @@ -383,12 +375,7 @@ 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 = 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_provider_lazy = make_lazy_provider_mock("MockVoyageProvider", mock_provider_class) 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 5d71062d3..f67a5f9ff 100644 --- a/tests/integration/providers/env_registry/test_definitions.py +++ b/tests/integration/providers/env_registry/test_definitions.py @@ -29,6 +29,7 @@ from codeweaver.providers.env_registry.registry import ProviderEnvRegistry +@pytest.mark.integration class TestOpenAIProvider: """Test OPENAI base provider configuration.""" @@ -85,6 +86,7 @@ def test_openai_no_inheritance(self) -> None: assert OPENAI.inherits_from is None +@pytest.mark.integration class TestDeepSeekProvider: """Test DEEPSEEK provider configuration.""" @@ -111,6 +113,7 @@ def test_deepseek_note(self) -> None: assert "DeepSeek" in DEEPSEEK.note +@pytest.mark.integration class TestFireworksProvider: """Test FIREWORKS provider configuration.""" @@ -137,6 +140,7 @@ def test_fireworks_inheritance(self) -> None: assert FIREWORKS.inherits_from == "openai" +@pytest.mark.integration class TestTogetherProvider: """Test TOGETHER provider configuration.""" @@ -162,6 +166,7 @@ def test_together_note(self) -> None: assert "Together" in TOGETHER.note +@pytest.mark.integration class TestCerebrasProvider: """Test CEREBRAS provider configuration.""" @@ -187,6 +192,7 @@ def test_cerebras_inheritance(self) -> None: assert CEREBRAS.inherits_from == "openai" +@pytest.mark.integration class TestMoonshotProvider: """Test MOONSHOT provider configuration.""" @@ -207,6 +213,7 @@ def test_moonshot_inheritance(self) -> None: assert MOONSHOT.inherits_from == "openai" +@pytest.mark.integration class TestMorphProvider: """Test MORPH provider configuration.""" @@ -233,6 +240,7 @@ def test_morph_inheritance(self) -> None: assert MORPH.inherits_from == "openai" +@pytest.mark.integration class TestNebiusProvider: """Test NEBIUS provider configuration.""" @@ -258,6 +266,7 @@ def test_nebius_inheritance(self) -> None: assert NEBIUS.inherits_from == "openai" +@pytest.mark.integration class TestOpenRouterProvider: """Test OPENROUTER provider configuration.""" @@ -278,6 +287,7 @@ def test_openrouter_inheritance(self) -> None: assert OPENROUTER.inherits_from == "openai" +@pytest.mark.integration class TestOVHCloudProvider: """Test OVHCLOUD provider configuration.""" @@ -303,6 +313,7 @@ def test_ovhcloud_inheritance(self) -> None: assert OVHCLOUD.inherits_from == "openai" +@pytest.mark.integration class TestSambaNovaProvider: """Test SAMBANOVA provider configuration.""" @@ -328,6 +339,7 @@ def test_sambanova_inheritance(self) -> None: assert SAMBANOVA.inherits_from == "openai" +@pytest.mark.integration class TestGroqProvider: """Test GROQ provider configuration.""" @@ -357,6 +369,7 @@ def test_groq_inheritance(self) -> None: assert GROQ.inherits_from == "openai" +@pytest.mark.integration class TestRegistryAutoDiscovery: """Test registry auto-discovery of provider definitions.""" @@ -410,6 +423,7 @@ 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.""" @@ -449,6 +463,7 @@ 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.""" @@ -487,6 +502,7 @@ 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 4d630d8a5..d358d0712 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.value + mock_provider.circuit_breaker_state = CircuitBreakerState.CLOSED.variable 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.value + mock_provider.circuit_breaker_state = CircuitBreakerState.CLOSED.variable 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.value + mock_provider.circuit_breaker_state = CircuitBreakerState.CLOSED.variable 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.value + provider.circuit_breaker_state = CircuitBreakerState.OPEN.variable 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.value + provider.circuit_breaker_state = CircuitBreakerState.OPEN.variable 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.value + provider.circuit_breaker_state = CircuitBreakerState.HALF_OPEN.variable # 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.value + provider.circuit_breaker_state = CircuitBreakerState.CLOSED.variable 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 d9b0b6402..c65b381e3 100644 --- a/tests/integration/server/test_health_monitoring.py +++ b/tests/integration/server/test_health_monitoring.py @@ -34,6 +34,7 @@ from codeweaver.core import FailoverStats, Identifier, SessionStatistics from codeweaver.engine import IndexingService, IndexingStats +from codeweaver.providers import CircuitBreakerState from codeweaver.server import ( HealthResponse, HealthService, @@ -108,7 +109,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 = "closed" + embedding_instance.circuit_breaker_state.variable = CircuitBreakerState.CLOSED.variable # Mock sparse embedding provider sparse_instance = mocker.MagicMock() @@ -119,7 +120,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 = "closed" + reranking_instance.circuit_breaker_state.variable = CircuitBreakerState.CLOSED.variable return { "embedding": (embedding_instance,), @@ -325,8 +326,7 @@ 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] - # FIX: Use .variable instead of .value to match BaseEnum interface - embedding_instance.circuit_breaker_state.variable = "open" + embedding_instance.circuit_breaker_state.variable = CircuitBreakerState.OPEN.variable response = await health_service.get_health_response() @@ -429,16 +429,14 @@ async def test_health_circuit_breaker_exposure(health_service: HealthService, mo # Test half_open state embedding_instance = health_service._providers["embedding"][0] - # FIX: Use .variable instead of .value to match BaseEnum interface - embedding_instance.circuit_breaker_state.variable = "half_open" + embedding_instance.circuit_breaker_state.variable = CircuitBreakerState.HALF_OPEN.variable 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) - # FIX: Use .variable instead of .value to match BaseEnum interface - embedding_instance.circuit_breaker_state.variable = "open" + embedding_instance.circuit_breaker_state.variable = CircuitBreakerState.OPEN.variable 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 c5544e6ea..5e7fdc3af 100644 --- a/tests/unit/cli/test_httpx_lazy_import.py +++ b/tests/unit/cli/test_httpx_lazy_import.py @@ -27,6 +27,10 @@ @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 fd394306d..06ebfc6c4 100644 --- a/tests/unit/config/test_versioned_profile.py +++ b/tests/unit/config/test_versioned_profile.py @@ -15,6 +15,7 @@ from codeweaver.providers.config.sdk import VoyageEmbeddingConfig +@pytest.mark.unit class TestVersionedProfile: """Test suite for VersionedProfile dataclass.""" @@ -209,6 +210,7 @@ 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 e467ea874..c309c7463 100644 --- a/tests/unit/core/telemetry/test_privacy.py +++ b/tests/unit/core/telemetry/test_privacy.py @@ -61,6 +61,7 @@ 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 new file mode 100644 index 000000000..4f47f8b4a --- /dev/null +++ b/tests/unit/core/test_discovery.py @@ -0,0 +1,96 @@ +# SPDX-FileCopyrightText: 2026 Knitli Inc. +# SPDX-FileContributor: Adam Poulemanos +# +# SPDX-License-Identifier: MIT OR Apache-2.0 + +"""Unit tests for core discovery logic.""" + +from pathlib import Path +from unittest.mock import patch + +import pytest + +from codeweaver.core.discovery import DiscoveredFile +from codeweaver.core.metadata import ExtCategory + + +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 test_is_path_binary_exception_handling(): + # Arrange + test_path = Path("some_nonexistent_or_protected_file.bin") + + # Act & Assert + with patch("pathlib.Path.open", side_effect=PermissionError("Permission denied")): + result = DiscoveredFile.is_path_binary(test_path) + assert result is False + + with patch("pathlib.Path.open", side_effect=OSError("OS Error")): + result = DiscoveredFile.is_path_binary(test_path) + assert result is False diff --git a/uv.lock b/uv.lock index bf6adf77b..71d2b4cf3 100644 --- a/uv.lock +++ b/uv.lock @@ -157,7 +157,7 @@ wheels = [ [[package]] name = "anthropic" -version = "0.79.0" +version = "0.84.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/15/b1/91aea3f8fd180d01d133d931a167a78a3737b3fd39ccef2ae8d6619c24fd/anthropic-0.79.0.tar.gz", hash = "sha256:8707aafb3b1176ed6c13e2b1c9fb3efddce90d17aee5d8b83a86c70dcdcca871", size = 509825, upload-time = "2026-02-07T18:06:18.388Z" } +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" } wheels = [ - { 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" }, + { 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" }, ] [[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.1" }, - { name = "cyclopts", specifier = ">=4.5.1" }, + { name = "cohere", specifier = "==5.20.7" }, + { name = "cyclopts", specifier = ">=4.10.0" }, { 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 = "==0.36.2" }, + { name = "huggingface-hub", specifier = ">=1.7.1" }, { name = "lateimport", specifier = ">=0.1.0" }, - { name = "mcp", specifier = ">=1.19.0" }, + { name = "mcp", specifier = ">=1.23.3" }, { name = "mistralai", specifier = "==1.10.0" }, { name = "numpy", specifier = ">=2.4.2" }, - { name = "openai", specifier = "==2.17.0" }, + { name = "openai", specifier = "==2.28.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.2" }, + { name = "platformdirs", specifier = ">=4.9.4" }, { 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.56.0" }, + { name = "pydantic-ai-slim", specifier = ">=1.68.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.12.0" }, - { name = "qdrant-client", specifier = "==1.16.2" }, + { name = "pydantic-settings", extras = ["toml", "yaml"], specifier = ">=2.13.1" }, + { name = "qdrant-client", specifier = "==1.17.1" }, { name = "qdrant-client", marker = "extra == 'in-memory'" }, { name = "qdrant-client", marker = "extra == 'qdrant'" }, - { name = "rich", specifier = ">=14.3.0" }, + { name = "rich", specifier = ">=14.3.3" }, { 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.1" +version = "5.20.7" 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/4b/ed/bb02083654bdc089ae4ef1cd7691fd2233f1fd9f32bcbfacc80ff57d9775/cohere-5.20.1.tar.gz", hash = "sha256:50973f63d2c6138ff52ce37d8d6f78ccc539af4e8c43865e960d68e0bf835b6f", size = 180820, upload-time = "2025-12-18T16:39:50.975Z" } +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" } wheels = [ - { 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" }, + { 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" }, ] [[package]] @@ -1552,7 +1552,7 @@ wheels = [ [[package]] name = "fastembed-gpu" -version = "0.7.3" +version = "0.7.4" 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/de/b0/9d528c2dfc319d218a9829b9018e480cd23d620492636817321ad0fb5cce/fastembed_gpu-0.7.3.tar.gz", hash = "sha256:2ed106290677b4cc93e3a8467fd3fbcbf288c1e11fa02cebed67f02a7ccb2427", size = 66636, upload-time = "2025-08-29T11:20:05.13Z" } +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" } wheels = [ - { 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" }, + { 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" }, ] [[package]] @@ -2017,31 +2017,34 @@ wheels = [ [[package]] name = "hf-xet" -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" }, +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" }, ] [[package]] @@ -2133,26 +2136,22 @@ wheels = [ [[package]] name = "huggingface-hub" -version = "0.36.2" +version = "1.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, { name = "fsspec" }, - { 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 = "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 = "packaging" }, { name = "pyyaml" }, - { name = "requests" }, { name = "tqdm" }, + { name = "typer" }, { name = "typing-extensions" }, ] -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" } +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" } wheels = [ - { 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" }, + { 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" }, ] [[package]] @@ -3466,7 +3465,7 @@ wheels = [ [[package]] name = "openai" -version = "2.17.0" +version = "2.28.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -3478,9 +3477,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -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" } +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" } wheels = [ - { 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" }, + { 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" }, ] [[package]] @@ -3814,11 +3813,11 @@ wheels = [ [[package]] name = "platformdirs" -version = "4.9.2" +version = "4.9.4" source = { registry = "https://pypi.org/simple" } -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" } +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" } wheels = [ - { 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" }, + { 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" }, ] [[package]] @@ -4183,20 +4182,20 @@ email = [ [[package]] name = "pydantic-ai-slim" -version = "1.56.0" +version = "1.68.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "genai-prices" }, - { name = "griffe" }, + { name = "griffelib" }, { name = "httpx" }, { name = "opentelemetry-api" }, { name = "pydantic" }, { name = "pydantic-graph" }, { name = "typing-inspection" }, ] -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" } +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" } wheels = [ - { 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" }, + { 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" }, ] [package.optional-dependencies] @@ -4219,7 +4218,7 @@ groq = [ { name = "groq" }, ] huggingface = [ - { name = "huggingface-hub", extra = ["inference"] }, + { name = "huggingface-hub" }, ] mistral = [ { name = "mistralai" }, @@ -4308,7 +4307,7 @@ wheels = [ [[package]] name = "pydantic-graph" -version = "1.56.0" +version = "1.68.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "httpx" }, @@ -4316,23 +4315,23 @@ dependencies = [ { name = "pydantic" }, { name = "typing-inspection" }, ] -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" } +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" } wheels = [ - { 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" }, + { 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" }, ] [[package]] name = "pydantic-settings" -version = "2.12.0" +version = "2.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, { name = "typing-inspection" }, ] -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" } +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" } wheels = [ - { 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" }, + { 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" }, ] [package.optional-dependencies] @@ -4671,7 +4670,7 @@ wheels = [ [[package]] name = "qdrant-client" -version = "1.16.2" +version = "1.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "grpcio" }, @@ -4682,9 +4681,9 @@ dependencies = [ { name = "pydantic" }, { name = "urllib3" }, ] -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" } +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" } wheels = [ - { 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" }, + { 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" }, ] [[package]] @@ -4840,15 +4839,15 @@ wheels = [ [[package]] name = "rich" -version = "14.3.2" +version = "14.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -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" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl", hash = "sha256:08e67c3e90884651da3239ea668222d19bea7b589149d8014a21c633420dbb69", size = 309963, upload-time = "2026-02-01T16:20:46.078Z" }, + { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" }, ] [[package]] @@ -5588,23 +5587,22 @@ wheels = [ [[package]] name = "transformers" -version = "4.57.1" +version = "5.3.0" 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/d6/68/a39307bcc4116a30b2106f2e689130a48de8bd8a1e635b5e1030e46fcd9e/transformers-4.57.1.tar.gz", hash = "sha256:f06c837959196c75039809636cd964b959f6604b75b8eeec6fdfc0440b89cc55", size = 10142511, upload-time = "2025-10-14T15:39:26.18Z" } +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" } wheels = [ - { 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" }, + { 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" }, ] [[package]]