From 3a2c03061ce912ff7421286c8197f844b63bbefb Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Fri, 29 May 2026 13:24:12 -0700 Subject: [PATCH] =?UTF-8?q?fix(stt,tts):=20restore=20mistralai=20=E2=80=94?= =?UTF-8?q?=202.4.8=20is=20clean,=20ban=20lifted=20(#34841)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs(code-execution): document HERMES_* env narrowing + passthrough workaround The execute_code sandbox-child env scrub (108397726, #27303) deliberately dropped the broad HERMES_ prefix passthrough, keeping only an operational 4-var allowlist (HERMES_HOME/PROFILE/CONFIG/ENV). A script that relied on a non-secret HERMES_* var (HERMES_BASE_URL, HERMES_KANBAN_DB, HERMES_*_WEBHOOK, or a plugin-defined one) now sees it unset in the child. Document the behavior change and the two recovery routes (terminal.env_passthrough in config.yaml, or required_environment_variables in skill frontmatter), plus the debug log line that surfaces the drop for diagnosis. * fix(stt,tts): restore mistralai — 2.4.8 is clean, ban lifted PyPI quarantined mistralai on 2026-05-12 after the malicious 2.4.6 release (Mini Shai-Hulud worm). 2.4.6 has since been removed from the registry and clean releases resumed (2.4.7 2026-05-25, 2.4.8 2026-05-28). This rolls back the blanket runtime ban so Voxtral STT + TTS work again, following the restoration checklist the repo left in pyproject.toml. Verified against the real SDK: 2.4.8 keeps the import path the code uses (from mistralai.client import Mistral) and the audio.transcriptions.complete / audio.speech.complete surfaces. Changes: - pyproject.toml: re-add mistral extra pinned to mistralai==2.4.8; left OUT of [all] per the 2026-05-12 lazy-install policy (one quarantined release must not break fresh installs). uv.lock regenerated. - tools/lazy_deps.py: add stt.mistral / tts.mistral entries so the SDK lazy-installs on first use (matches edge / elevenlabs). - tools/transcription_tools.py: restore explicit-provider gate (_HAS_MISTRAL + key) and auto-detect entry (local>groq>openai>mistral>xai); _transcribe_mistral lazy-installs before import. - tools/tts_tool.py: dispatcher routes back to _generate_mistral_tts; _import_mistral_client lazy-installs the SDK. - hermes_cli/tools_config.py, hermes_cli/web_server.py: un-hide Mistral from the TTS provider picker and dashboard STT options. - hermes_cli/security_advisories.py: KEEP the shai-hulud-2026-05 advisory (module policy forbids removal) — it is scoped to 2.4.6 only, so it still warns anyone with the poisoned build cached and never fires on 2.4.8. Summary note updated to reflect the un-quarantine. - tests: revert the disabled-behavior assertions added by the ban commit back to routing/positive expectations; add mistral to the lazy-installable-extras-excluded-from-[all] contract. Reported by @SkYNewZ (#34503). Validation: 189 targeted STT/TTS/lazy_deps/metadata tests pass; E2E with the real mistralai 2.4.8 SDK routes both STT and TTS to mistral. --- hermes_cli/security_advisories.py | 4 +- hermes_cli/tools_config.py | 13 ++++-- hermes_cli/web_server.py | 4 +- pyproject.toml | 25 ++++------- tests/test_project_metadata.py | 1 + .../test_transcription_dotenv_fallback.py | 8 +--- tests/tools/test_transcription_tools.py | 35 ++++----------- tests/tools/test_tts_mistral.py | 23 ++++------ tools/lazy_deps.py | 11 ++--- tools/transcription_tools.py | 28 ++++++------ tools/tts_tool.py | 40 ++++++++++------- uv.lock | 43 ++++++++++++++++++- 12 files changed, 130 insertions(+), 105 deletions(-) diff --git a/hermes_cli/security_advisories.py b/hermes_cli/security_advisories.py index 4b8394977..ef058a5a4 100644 --- a/hermes_cli/security_advisories.py +++ b/hermes_cli/security_advisories.py @@ -104,7 +104,9 @@ ADVISORIES: tuple[Advisory, ...] = ( "them to a hardcoded webhook. If you ran any Python process that " "imported mistralai 2.4.6 — including hermes when configured " "with provider=mistral for TTS or STT — assume those credentials " - "are exposed." + "are exposed. PyPI has since removed 2.4.6 and the project ships " + "clean releases again (2.4.7, 2.4.8); this advisory only fires if " + "the compromised 2.4.6 is still installed." ), url="https://socket.dev/blog/mini-shai-hulud-worm-pypi", compromised=( diff --git a/hermes_cli/tools_config.py b/hermes_cli/tools_config.py index 433b938c5..4b495d4d3 100644 --- a/hermes_cli/tools_config.py +++ b/hermes_cli/tools_config.py @@ -244,9 +244,16 @@ TOOL_CATEGORIES = { ], "tts_provider": "elevenlabs", }, - # Mistral (Voxtral TTS) temporarily hidden — `mistralai` PyPI - # package is currently quarantined (malicious 2.4.6 release on - # 2026-05-12). Restore this entry once PyPI un-quarantines. + # Mistral Voxtral TTS — `mistralai` SDK lazy-installs on first use. + { + "name": "Mistral (Voxtral TTS)", + "badge": "paid", + "tag": "Multilingual, native Opus", + "env_vars": [ + {"key": "MISTRAL_API_KEY", "prompt": "Mistral API key", "url": "https://console.mistral.ai/"}, + ], + "tts_provider": "mistral", + }, { "name": "Google Gemini TTS", "badge": "preview", diff --git a/hermes_cli/web_server.py b/hermes_cli/web_server.py index 0dbd79665..58e0d5990 100644 --- a/hermes_cli/web_server.py +++ b/hermes_cli/web_server.py @@ -320,9 +320,7 @@ _SCHEMA_OVERRIDES: Dict[str, Dict[str, Any]] = { "stt.provider": { "type": "select", "description": "Speech-to-text provider", - # "mistral" temporarily removed — mistralai PyPI package quarantined - # (malicious 2.4.6 release on 2026-05-12). Restore once available. - "options": ["local", "openai"], + "options": ["local", "openai", "mistral"], }, "display.skin": { "type": "select", diff --git a/pyproject.toml b/pyproject.toml index 88b39df4a..55fce4ec1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -117,22 +117,15 @@ sms = ["aiohttp==3.13.3"] # to it, which is already provided by the `mcp` extra. computer-use = ["mcp==1.26.0"] acp = ["agent-client-protocol==0.9.0"] -# mistral: extra REMOVED 2026-05-12 — `mistralai` PyPI project quarantined -# after malicious 2.4.6 release (Mini Shai-Hulud worm). Every version of -# `mistralai` returns 404 on PyPI right now, so any pin we'd write is -# unresolvable, which breaks `uv lock --check` in CI. -# -# To restore once PyPI un-quarantines: -# 1. Verify the new release is clean (read the changelog, check Socket -# advisory page, confirm no malicious code review findings). -# 2. Add back: mistral = ["mistralai=="] -# 3. Re-enable Mistral in: -# - tools/lazy_deps.py (LAZY_DEPS["tts.mistral"], LAZY_DEPS["stt.mistral"]) -# - hermes_cli/tools_config.py (un-hide from provider picker) -# - hermes_cli/web_server.py (re-add to dashboard STT options) -# - tools/transcription_tools.py / tools/tts_tool.py (drop disabled stubs) -# 4. Run `uv lock` to regenerate transitives. -# 5. Optionally re-add to [all] only after a few days of clean operation. +# mistral: Voxtral STT + TTS. Pinned to an exact verified-clean version. +# The `mistralai` PyPI project was quarantined 2026-05-12 after the malicious +# 2.4.6 release (Mini Shai-Hulud worm); 2.4.6 was removed from PyPI and the +# project is serving clean releases again (2.4.7 2026-05-25, 2.4.8 2026-05-28). +# Like other opt-in TTS/STT backends, this is lazy-installed via +# tools/lazy_deps.py (stt.mistral / tts.mistral) at first use — deliberately +# NOT re-added to [all] so a future quarantined release can't break fresh +# installs (see [all] policy comment below). +mistral = ["mistralai==2.4.8"] bedrock = ["boto3==1.42.89"] azure-identity = ["azure-identity==1.25.3"] termux = [ diff --git a/tests/test_project_metadata.py b/tests/test_project_metadata.py index 45afb3c1a..51ca9cf91 100644 --- a/tests/test_project_metadata.py +++ b/tests/test_project_metadata.py @@ -73,6 +73,7 @@ def test_lazy_installable_extras_excluded_from_all(): "modal", "daytona", "messaging", "slack", "matrix", "dingtalk", "feishu", "honcho", "hindsight", + "mistral", # mistralai — Voxtral STT/TTS, lazy-installed (stt.mistral / tts.mistral) } all_extra_specs = optional_dependencies["all"] for extra in lazy_covered_extras: diff --git a/tests/tools/test_transcription_dotenv_fallback.py b/tests/tools/test_transcription_dotenv_fallback.py index 5a0517c3b..e764ac0b4 100644 --- a/tests/tools/test_transcription_dotenv_fallback.py +++ b/tests/tools/test_transcription_dotenv_fallback.py @@ -99,12 +99,6 @@ class TestProviderSelectionGate: assert tt._get_provider({"enabled": True, "provider": "groq"}) == "groq" def test_explicit_mistral_sees_dotenv(self): - """Mistral STT is intentionally disabled (PyPI quarantine 2026-05-12). - - Even with the dotenv key visible, explicit `provider: mistral` must - return "none" with a warning. Restore the previous behavior once - `mistralai` is un-quarantined on PyPI. - """ from tools import transcription_tools as tt with patch.object(tt, "_HAS_FASTER_WHISPER", False), \ @@ -112,7 +106,7 @@ class TestProviderSelectionGate: patch.object(tt, "_has_local_command", return_value=False), \ patch("hermes_cli.config.load_env", return_value={"MISTRAL_API_KEY": "dotenv-secret"}): - assert tt._get_provider({"enabled": True, "provider": "mistral"}) == "none" + assert tt._get_provider({"enabled": True, "provider": "mistral"}) == "mistral" def test_explicit_xai_sees_dotenv(self): from tools import transcription_tools as tt diff --git a/tests/tools/test_transcription_tools.py b/tests/tools/test_transcription_tools.py index 0e1c0ef78..f3c0cf29c 100644 --- a/tests/tools/test_transcription_tools.py +++ b/tests/tools/test_transcription_tools.py @@ -1010,23 +1010,16 @@ class TestTranscribeMistral: # ============================================================================ class TestGetProviderMistral: - """Mistral-specific provider selection tests. - - Mistral STT is intentionally disabled in 2026-05-12+ while the - `mistralai` PyPI package is quarantined. These tests document that - explicit `provider: mistral` always returns "none" with a warning, and - that auto-detect skips mistral entirely. - """ + """Mistral-specific provider selection tests.""" def test_mistral_when_key_and_sdk_available(self, monkeypatch): - """Even with key + SDK, explicit mistral returns 'none' (disabled).""" monkeypatch.setenv("MISTRAL_API_KEY", "test-key") with patch("tools.transcription_tools._HAS_MISTRAL", True): from tools.transcription_tools import _get_provider - assert _get_provider({"provider": "mistral"}) == "none" + assert _get_provider({"provider": "mistral"}) == "mistral" def test_mistral_explicit_no_key_returns_none(self, monkeypatch): - """Explicit mistral with no key returns none.""" + """Explicit mistral with no key returns none — no cross-provider fallback.""" monkeypatch.delenv("MISTRAL_API_KEY", raising=False) with patch("tools.transcription_tools._HAS_MISTRAL", True): from tools.transcription_tools import _get_provider @@ -1039,23 +1032,18 @@ class TestGetProviderMistral: from tools.transcription_tools import _get_provider assert _get_provider({"provider": "mistral"}) == "none" - def test_auto_detect_skips_mistral(self, monkeypatch): - """Auto-detect intentionally skips mistral (quarantine workaround). - - With no other provider available but MISTRAL_API_KEY set, the result - must be 'none' — mistral is no longer in the auto-detect chain. - """ + def test_auto_detect_mistral_after_openai(self, monkeypatch): + """Auto-detect: mistral is tried after openai when both are unavailable.""" monkeypatch.delenv("GROQ_API_KEY", raising=False) monkeypatch.delenv("VOICE_TOOLS_OPENAI_KEY", raising=False) monkeypatch.delenv("OPENAI_API_KEY", raising=False) - monkeypatch.delenv("XAI_API_KEY", raising=False) monkeypatch.setenv("MISTRAL_API_KEY", "test-key") with patch("tools.transcription_tools._HAS_FASTER_WHISPER", False), \ patch("tools.transcription_tools._has_local_command", return_value=False), \ patch("tools.transcription_tools._HAS_OPENAI", False), \ patch("tools.transcription_tools._HAS_MISTRAL", True): from tools.transcription_tools import _get_provider - assert _get_provider({}) == "none" + assert _get_provider({}) == "mistral" def test_auto_detect_openai_preferred_over_mistral(self, monkeypatch): """Auto-detect: openai is preferred over mistral (both paid, openai more common).""" @@ -1329,13 +1317,8 @@ class TestGetProviderXAI: from tools.transcription_tools import _get_provider assert _get_provider({}) == "xai" - def test_auto_detect_mistral_skipped_xai_wins(self, monkeypatch): - """Auto-detect skips mistral entirely (quarantine) — xai wins. - - Even with MISTRAL_API_KEY set, mistral is no longer in the - auto-detect chain. xai is the next-best fallback when the - local/groq/openai chain is unavailable. - """ + def test_auto_detect_mistral_preferred_over_xai(self, monkeypatch): + """Auto-detect: mistral is preferred over xai.""" monkeypatch.setenv("MISTRAL_API_KEY", "test-key") monkeypatch.setenv("XAI_API_KEY", "xai-test") monkeypatch.delenv("GROQ_API_KEY", raising=False) @@ -1346,7 +1329,7 @@ class TestGetProviderXAI: patch("tools.transcription_tools._HAS_OPENAI", False), \ patch("tools.transcription_tools._HAS_MISTRAL", True): from tools.transcription_tools import _get_provider - assert _get_provider({}) == "xai" + assert _get_provider({}) == "mistral" def test_auto_detect_no_key_returns_none(self, monkeypatch): """Auto-detect: xai skipped when no key is set.""" diff --git a/tests/tools/test_tts_mistral.py b/tests/tools/test_tts_mistral.py index 818a6c1d1..6e98946b6 100644 --- a/tests/tools/test_tts_mistral.py +++ b/tests/tools/test_tts_mistral.py @@ -162,34 +162,27 @@ class TestGenerateMistralTts: class TestTtsDispatcherMistral: - def test_dispatcher_returns_disabled_error( + def test_dispatcher_routes_to_mistral( self, tmp_path, mock_mistral_module, monkeypatch ): - """Mistral TTS is intentionally disabled (PyPI quarantine 2026-05-12). - - The dispatcher must short-circuit with a clear status message before - attempting any SDK import, even when MISTRAL_API_KEY is set and a - mock SDK is wired in. Restore routing once `mistralai` is - un-quarantined on PyPI. - """ import json from tools.tts_tool import text_to_speech_tool monkeypatch.setenv("MISTRAL_API_KEY", "test-key") + mock_mistral_module.audio.speech.complete.return_value = MagicMock( + audio_data=base64.b64encode(b"audio").decode() + ) output_path = str(tmp_path / "out.mp3") with patch("tools.tts_tool._load_tts_config", return_value={"provider": "mistral"}): result = json.loads(text_to_speech_tool("Hello", output_path=output_path)) - assert result["success"] is False - assert "temporarily disabled" in result["error"] - assert "quarantined" in result["error"] - # SDK must not have been called. - mock_mistral_module.audio.speech.complete.assert_not_called() + assert result["success"] is True + assert result["provider"] == "mistral" + mock_mistral_module.audio.speech.complete.assert_called_once() def test_dispatcher_returns_error_when_sdk_not_installed(self, tmp_path, monkeypatch): - """Same disabled message regardless of SDK presence.""" import json from tools.tts_tool import text_to_speech_tool @@ -203,7 +196,7 @@ class TestTtsDispatcherMistral: ) assert result["success"] is False - assert "temporarily disabled" in result["error"] + assert "mistralai" in result["error"] class TestCheckTtsRequirementsMistral: diff --git a/tools/lazy_deps.py b/tools/lazy_deps.py index 393397349..a0926a435 100644 --- a/tools/lazy_deps.py +++ b/tools/lazy_deps.py @@ -97,15 +97,16 @@ LAZY_DEPS: dict[str, tuple[str, ...]] = { # (see comment at top of [project.dependencies]). When bumping, update # both this map AND the corresponding extra in pyproject.toml. # - # NOTE: tts.mistral / stt.mistral entries are intentionally absent — - # the `mistralai` PyPI project is quarantined as of 2026-05-12 (Mini - # Shai-Hulud worm). Re-add when PyPI restores a clean release; see - # comment in pyproject.toml above the (removed) `mistral` extra for - # the full restoration checklist. + # mistralai pin tracks the `mistral` extra in pyproject.toml. PyPI + # quarantined the project 2026-05-12 (malicious 2.4.6, Mini Shai-Hulud); + # 2.4.6 was removed and clean releases resumed (2.4.7, 2.4.8). Voxtral + # STT + TTS share the same SDK. + "tts.mistral": ("mistralai==2.4.8",), "tts.edge": ("edge-tts==7.2.7",), "tts.elevenlabs": ("elevenlabs==1.59.0",), # ─── Speech-to-text providers ────────────────────────────────────────── + "stt.mistral": ("mistralai==2.4.8",), "stt.faster_whisper": ( "faster-whisper==1.2.1", "sounddevice==0.5.5", diff --git a/tools/transcription_tools.py b/tools/transcription_tools.py index 92dbf59f3..4794d4568 100644 --- a/tools/transcription_tools.py +++ b/tools/transcription_tools.py @@ -792,16 +792,11 @@ def _get_provider(stt_config: dict) -> str: return "none" if provider == "mistral": - # `mistralai` PyPI package was quarantined on 2026-05-12 after a - # malicious 2.4.6 release. Refuse to use this provider until it's - # available again so we surface a clear message instead of an - # opaque ImportError mid-call. + if _HAS_MISTRAL and get_env_value("MISTRAL_API_KEY"): + return "mistral" logger.warning( - "STT provider 'mistral' (Voxtral Transcribe) is temporarily " - "disabled — `mistralai` PyPI package is quarantined " - "(malicious 2.4.6 release on 2026-05-12). Falling back to " - "another provider. Set stt.provider in config.yaml to 'local' " - "or 'openai' to silence this warning." + "STT provider 'mistral' configured but mistralai package " + "not installed or MISTRAL_API_KEY not set" ) return "none" @@ -817,9 +812,7 @@ def _get_provider(stt_config: dict) -> str: return provider # Unknown — let it fail downstream - # --- Auto-detect (no explicit provider): local > groq > openai > xai --- - # mistral is intentionally skipped while `mistralai` is quarantined on - # PyPI (malicious 2.4.6 release on 2026-05-12). + # --- Auto-detect (no explicit provider): local > groq > openai > mistral > xai --- if _HAS_FASTER_WHISPER: return "local" @@ -834,6 +827,12 @@ def _get_provider(stt_config: dict) -> str: if _HAS_OPENAI and _has_openai_audio_backend(): logger.info("No local STT available, using OpenAI Whisper API") return "openai" + # Only auto-select Mistral if the SDK is already present — don't trigger a + # lazy-install during passive auto-detection. Explicit `provider: mistral` + # (above) does lazy-install on first transcription call. + if _HAS_MISTRAL and get_env_value("MISTRAL_API_KEY"): + logger.info("No local STT available, using Mistral Voxtral Transcribe API") + return "mistral" try: from tools.xai_http import resolve_xai_http_credentials @@ -1371,6 +1370,11 @@ def _transcribe_mistral(file_path: str, model_name: str) -> Dict[str, Any]: return {"success": False, "transcript": "", "error": "MISTRAL_API_KEY not set"} try: + try: + from tools.lazy_deps import ensure as _lazy_ensure + _lazy_ensure("stt.mistral", prompt=False) + except ImportError: + pass from mistralai.client import Mistral with Mistral(api_key=api_key) as client: diff --git a/tools/tts_tool.py b/tools/tts_tool.py index 95507bfdf..cab2cc584 100644 --- a/tools/tts_tool.py +++ b/tools/tts_tool.py @@ -121,7 +121,20 @@ def _import_openai_client(): return OpenAIClient def _import_mistral_client(): - """Lazy import Mistral client. Returns the class or raises ImportError.""" + """Lazy import Mistral client. Returns the class or raises ImportError. + + Calls :func:`tools.lazy_deps.ensure` first so the ``mistralai`` SDK gets + installed on demand if the user picked Mistral as their STT/TTS provider + but never ran the post-setup hook (e.g. enabled it by editing config.yaml + directly). Mirrors the ElevenLabs lazy-import path. + """ + try: + from tools.lazy_deps import ensure + ensure("tts.mistral", prompt=False) + except ImportError: + pass + except Exception as e: # FeatureUnavailable or any unexpected error + raise ImportError(str(e)) from mistralai.client import Mistral return Mistral @@ -1974,21 +1987,16 @@ def text_to_speech_tool( _generate_xai_tts(text, file_str, tts_config) elif provider == "mistral": - # `mistralai` PyPI package was quarantined on 2026-05-12 after a - # malicious 2.4.6 release. Surface a clear status message instead - # of attempting an import that would either fail or pull a stale - # cached package. - return json.dumps({ - "success": False, - "error": ( - "Mistral Voxtral TTS is temporarily disabled. The " - "`mistralai` PyPI package was quarantined on 2026-05-12 " - "after a malicious 2.4.6 release. Switch tts.provider in " - "config.yaml to 'edge', 'elevenlabs', 'openai', 'minimax', " - "'gemini', 'xai', 'neutts', or 'kittentts'. Mistral " - "support will return once PyPI un-quarantines the package." - ), - }, ensure_ascii=False) + try: + _import_mistral_client() + except ImportError: + return json.dumps({ + "success": False, + "error": "Mistral provider selected but 'mistralai' package not installed. " + "Run: pip install 'hermes-agent[mistral]'" + }, ensure_ascii=False) + logger.info("Generating speech with Mistral Voxtral TTS...") + _generate_mistral_tts(text, file_str, tts_config) elif provider == "gemini": logger.info("Generating speech with Google Gemini TTS...") diff --git a/uv.lock b/uv.lock index f3ef7d63f..84674830f 100644 --- a/uv.lock +++ b/uv.lock @@ -1243,6 +1243,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/97/a8/c070e1340636acb38d4e6a7e45c46d168a462b48b9b3257e14ca0e5af79b/environs-14.6.0-py3-none-any.whl", hash = "sha256:f8fb3d6c6a55872b0c6db077a28f5a8c7b8984b7c32029613d44cef95cfc0812", size = 17205, upload-time = "2026-02-20T04:02:07.299Z" }, ] +[[package]] +name = "eval-type-backport" +version = "0.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/a3/cafafb4558fd638aadfe4121dc6cefb8d743368c085acb2f521df0f3d9d7/eval_type_backport-0.3.1.tar.gz", hash = "sha256:57e993f7b5b69d271e37482e62f74e76a0276c82490cf8e4f0dffeb6b332d5ed", size = 9445, upload-time = "2025-12-02T11:51:42.987Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/22/fdc2e30d43ff853720042fa15baa3e6122722be1a7950a98233ebb55cd71/eval_type_backport-0.3.1-py3-none-any.whl", hash = "sha256:279ab641905e9f11129f56a8a78f493518515b83402b860f6f06dd7c011fdfa8", size = 6063, upload-time = "2025-12-02T11:51:41.665Z" }, +] + [[package]] name = "exa-py" version = "2.10.2" @@ -1715,6 +1724,9 @@ messaging = [ { name = "slack-bolt" }, { name = "slack-sdk" }, ] +mistral = [ + { name = "mistralai" }, +] modal = [ { name = "modal" }, ] @@ -1840,6 +1852,7 @@ requires-dist = [ { name = "mcp", marker = "extra == 'computer-use'", specifier = "==1.26.0" }, { name = "mcp", marker = "extra == 'dev'", specifier = "==1.26.0" }, { name = "mcp", marker = "extra == 'mcp'", specifier = "==1.26.0" }, + { name = "mistralai", marker = "extra == 'mistral'", specifier = "==2.4.8" }, { name = "modal", marker = "extra == 'modal'", specifier = "==1.3.4" }, { name = "numpy", marker = "extra == 'voice'", specifier = "==2.4.3" }, { name = "openai", specifier = "==2.24.0" }, @@ -1876,7 +1889,7 @@ requires-dist = [ { name = "uvicorn", extras = ["standard"], marker = "extra == 'web'", specifier = "==0.41.0" }, { name = "youtube-transcript-api", marker = "extra == 'youtube'", specifier = "==1.2.4" }, ] -provides-extras = ["anthropic", "exa", "firecrawl", "parallel-web", "fal", "edge-tts", "modal", "daytona", "hindsight", "dev", "messaging", "cron", "slack", "matrix", "wecom", "cli", "tts-premium", "voice", "pty", "honcho", "mcp", "homeassistant", "sms", "computer-use", "acp", "bedrock", "azure-identity", "termux", "termux-all", "dingtalk", "feishu", "google", "youtube", "web", "all"] +provides-extras = ["anthropic", "exa", "firecrawl", "parallel-web", "fal", "edge-tts", "modal", "daytona", "hindsight", "dev", "messaging", "cron", "slack", "matrix", "wecom", "cli", "tts-premium", "voice", "pty", "honcho", "mcp", "homeassistant", "sms", "computer-use", "acp", "mistral", "bedrock", "azure-identity", "termux", "termux-all", "dingtalk", "feishu", "google", "youtube", "web", "all"] [[package]] name = "hf-xet" @@ -2206,6 +2219,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" }, ] +[[package]] +name = "jsonpath-python" +version = "1.1.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/18/4ca8742534a5993ff383f7602e325ce2d5d7cc93d72ac5e1cdedbea8a458/jsonpath_python-1.1.6.tar.gz", hash = "sha256:dded9932b4ec41fb8726e09c83afa4e6be618f938c2db287cc2a81723c639671", size = 88178, upload-time = "2026-05-07T01:26:34.482Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl", hash = "sha256:a1c50afd8d3fbbaf47a4873bc890dcb3c15da96f5c020327977d844d8731a2d4", size = 14453, upload-time = "2026-05-07T01:26:33.306Z" }, +] + [[package]] name = "jsonschema" version = "4.26.0" @@ -2408,6 +2430,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] +[[package]] +name = "mistralai" +version = "2.4.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "eval-type-backport" }, + { name = "httpx" }, + { name = "jsonpath-python" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "pydantic" }, + { name = "python-dateutil" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/1c/04119828a3da3be8c79efbe59035a621ae22af873c1ee5a4200355025aa6/mistralai-2.4.8.tar.gz", hash = "sha256:4f27b9b7dfd564ae111d3d9992d2a8ad1454aaf3e7675554c686aa3bb89617e2", size = 464443, upload-time = "2026-05-28T10:00:45.72Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/2a/d9952a97596ff9570ff7f486084ebfc5637b1bcf62084b97c0f8415713fc/mistralai-2.4.8-py3-none-any.whl", hash = "sha256:edc445c8b5edf332d45db6c708cd1e4d3f62e6eba5d2e8bf3969bdc5117f6472", size = 1110598, upload-time = "2026-05-28T10:00:43.939Z" }, +] + [[package]] name = "modal" version = "1.3.4"