Co-authored-by: Maxime Dolores <maxime.dolores@ext.mistral.ai>
Co-authored-by: Michel Thomazo <51709227+michelTho@users.noreply.github.com>
Co-authored-by: Peter Evers <peter.evers@mistral.ai>
Co-authored-by: Pierre Rossinès <pierre.rossines@mistral.ai>
Co-authored-by: Quentin <quentin.torroba@mistral.ai>
Co-authored-by: Val <102326092+vdeva@users.noreply.github.com>
Co-authored-by: Vincent G <10739306+VinceOPS@users.noreply.github.com>
Co-authored-by: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
Clément Drouin 2026-05-29 16:17:54 +02:00 committed by GitHub
parent 198277af3f
commit ad0d5c9520
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
61 changed files with 969 additions and 461 deletions

View file

@ -315,7 +315,7 @@ class TestAdapterPrepareRequest:
payload = json.loads(req.body)
assert payload["model"] == "claude-sonnet-4-20250514"
assert payload["max_tokens"] == 1024
assert payload["temperature"] == 0.5
assert "temperature" not in payload
assert req.endpoint == "/v1/messages"
assert req.headers["anthropic-version"] == "2023-06-01"
@ -392,9 +392,10 @@ class TestAdapterPrepareRequest:
thinking="medium",
)
payload = json.loads(req.body)
assert payload["thinking"] == {"type": "enabled", "budget_tokens": 10000}
assert payload["thinking"] == {"type": "adaptive", "display": "summarized"}
assert payload["output_config"] == {"effort": "medium"}
assert payload["max_tokens"] == 1024
assert payload["temperature"] == 1
assert "temperature" not in payload
def test_system_cached(self, adapter, provider):
messages = [
@ -439,12 +440,8 @@ class TestAdapterPrepareRequest:
assert len(payload["tools"]) == 1
assert payload["tools"][0]["name"] == "test_tool"
@pytest.mark.parametrize(
"level,expected_budget", [("low", 1024), ("medium", 10_000), ("high", 32_000)]
)
def test_thinking_levels_budget_model(
self, adapter, provider, level, expected_budget
):
@pytest.mark.parametrize("level", ["low", "medium", "high", "max"])
def test_thinking_levels(self, adapter, provider, level):
messages = [LLMMessage(role=Role.user, content="Hello")]
req = adapter.prepare_request(
model_name="claude-sonnet-4-20250514",
@ -458,59 +455,12 @@ class TestAdapterPrepareRequest:
thinking=level,
)
payload = json.loads(req.body)
assert payload["thinking"] == {
"type": "enabled",
"budget_tokens": expected_budget,
}
assert payload["temperature"] == 1
assert payload["max_tokens"] == expected_budget + 8192
@pytest.mark.parametrize(
"model_name", ["claude-opus-4-6-20260101", "claude-opus-4-7-20260418"]
)
@pytest.mark.parametrize("level", ["low", "medium", "high"])
def test_thinking_levels_adaptive_model(self, adapter, provider, model_name, level):
messages = [LLMMessage(role=Role.user, content="Hello")]
req = adapter.prepare_request(
model_name=model_name,
messages=messages,
temperature=0.5,
tools=None,
max_tokens=None,
tool_choice=None,
enable_streaming=False,
provider=provider,
thinking=level,
)
payload = json.loads(req.body)
assert payload["thinking"] == {"type": "adaptive", "display": "summarized"}
assert payload["output_config"] == {"effort": level}
if "opus-4-7" in model_name:
assert "temperature" not in payload
else:
assert payload["temperature"] == 1
assert "temperature" not in payload
assert payload["max_tokens"] == 32_768
@pytest.mark.parametrize("thinking_level", ["off", "low", "medium", "high"])
def test_temperature_omitted_for_deprecated_model(
self, adapter, provider, thinking_level
):
messages = [LLMMessage(role=Role.user, content="Hello")]
req = adapter.prepare_request(
model_name="claude-opus-4-7-20260418",
messages=messages,
temperature=0.5,
tools=None,
max_tokens=None,
tool_choice=None,
enable_streaming=False,
provider=provider,
thinking=thinking_level,
)
payload = json.loads(req.body)
assert "temperature" not in payload
def test_history_forced_thinking_budget_model(self, adapter, provider):
def test_history_forced_thinking(self, adapter, provider):
messages = [
LLMMessage(role=Role.user, content="Hello"),
LLMMessage(
@ -532,34 +482,9 @@ class TestAdapterPrepareRequest:
provider=provider,
)
payload = json.loads(req.body)
assert payload["thinking"] == {"type": "enabled", "budget_tokens": 10_000}
assert payload["temperature"] == 1
assert payload["max_tokens"] == 18_192
def test_history_forced_thinking_adaptive_model(self, adapter, provider):
messages = [
LLMMessage(role=Role.user, content="Hello"),
LLMMessage(
role=Role.assistant,
content="Answer",
reasoning_content="thinking...",
reasoning_signature="sig",
),
LLMMessage(role=Role.user, content="Follow up"),
]
req = adapter.prepare_request(
model_name="claude-opus-4-6-20260101",
messages=messages,
temperature=0.5,
tools=None,
max_tokens=None,
tool_choice=None,
enable_streaming=False,
provider=provider,
)
payload = json.loads(req.body)
assert payload["thinking"] == {"type": "adaptive", "display": "summarized"}
assert payload["output_config"] == {"effort": "medium"}
assert "temperature" not in payload
assert payload["max_tokens"] == 32_768

View file

@ -0,0 +1,140 @@
from __future__ import annotations
from collections.abc import Iterator
from dataclasses import dataclass
from datetime import UTC, datetime, timedelta
from ipaddress import IPv4Address
from pathlib import Path
import ssl
from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509.oid import ExtendedKeyUsageOID, NameOID
import pytest
from tests.e2e.mock_server import StreamingMockServer
from vibe.core.config import ModelConfig, ProviderConfig
from vibe.core.llm.backend.generic import GenericBackend
from vibe.core.types import Backend, LLMMessage, Role
from vibe.core.utils import build_ssl_context, configure_ssl_context
@dataclass(frozen=True)
class _TLSMaterial:
ca_file: str
cert_file: str
key_file: str
@dataclass(frozen=True)
class _HttpsStreamingMockServer:
server: StreamingMockServer
ca_file: str
@pytest.fixture
def https_streaming_mock_server(tmp_path: Path) -> Iterator[_HttpsStreamingMockServer]:
tls = _write_tls_material(tmp_path)
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ssl_context.load_cert_chain(certfile=tls.cert_file, keyfile=tls.key_file)
server = StreamingMockServer(ssl_context=ssl_context)
server.start()
try:
yield _HttpsStreamingMockServer(server=server, ca_file=tls.ca_file)
finally:
server.stop()
@pytest.mark.asyncio
async def test_generic_backend_streaming_uses_ssl_cert_file(
monkeypatch: pytest.MonkeyPatch,
https_streaming_mock_server: _HttpsStreamingMockServer,
) -> None:
monkeypatch.setenv("SSL_CERT_FILE", https_streaming_mock_server.ca_file)
monkeypatch.delenv("SSL_CERT_DIR", raising=False)
configure_ssl_context(enable_system_trust_store=False)
build_ssl_context.cache_clear()
chunks = []
try:
provider = ProviderConfig(
name="mock-provider",
api_base=https_streaming_mock_server.server.api_base,
api_key_env_var="MISTRAL_API_KEY",
backend=Backend.GENERIC,
)
model = ModelConfig(
name="mock-model", provider="mock-provider", alias="mock-model"
)
async with GenericBackend(provider=provider, timeout=5.0) as backend:
chunks = [
chunk
async for chunk in backend.complete_streaming(
model=model, messages=[LLMMessage(role=Role.user, content="Greet")]
)
]
finally:
configure_ssl_context(enable_system_trust_store=False)
build_ssl_context.cache_clear()
content = "".join(chunk.message.content or "" for chunk in chunks)
request_payload = https_streaming_mock_server.server.requests[-1]
assert content == "Hello from mock server"
assert request_payload.get("stream") is True
assert request_payload.get("model") == "mock-model"
def _write_tls_material(tmp_path: Path) -> _TLSMaterial:
now = datetime.now(UTC)
ca_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
ca_name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "Vibe test CA")])
ca_cert = (
x509.CertificateBuilder()
.subject_name(ca_name)
.issuer_name(ca_name)
.public_key(ca_key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(now - timedelta(minutes=1))
.not_valid_after(now + timedelta(days=1))
.add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
.sign(ca_key, hashes.SHA256())
)
server_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
server_name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "127.0.0.1")])
server_cert = (
x509.CertificateBuilder()
.subject_name(server_name)
.issuer_name(ca_cert.subject)
.public_key(server_key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(now - timedelta(minutes=1))
.not_valid_after(now + timedelta(days=1))
.add_extension(
x509.SubjectAlternativeName([x509.IPAddress(IPv4Address("127.0.0.1"))]),
critical=False,
)
.add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=True)
.add_extension(
x509.ExtendedKeyUsage([ExtendedKeyUsageOID.SERVER_AUTH]), critical=False
)
.sign(ca_key, hashes.SHA256())
)
ca_file = tmp_path / "ca.pem"
cert_file = tmp_path / "server.pem"
key_file = tmp_path / "server.key"
ca_file.write_bytes(ca_cert.public_bytes(serialization.Encoding.PEM))
cert_file.write_bytes(server_cert.public_bytes(serialization.Encoding.PEM))
key_file.write_bytes(
server_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
)
)
return _TLSMaterial(
ca_file=str(ca_file), cert_file=str(cert_file), key_file=str(key_file)
)

View file

@ -91,7 +91,7 @@ class TestPrepareRequest:
assert payload["anthropic_version"] == "vertex-2023-10-16"
assert "model" not in payload
assert payload["max_tokens"] == 1024
assert payload["temperature"] == 0.5
assert "temperature" not in payload
assert req.headers["Authorization"] == "Bearer fake-token"
assert req.headers["anthropic-beta"] == adapter.BETA_FEATURES
assert "rawPredict" in req.endpoint
@ -147,9 +147,10 @@ class TestPrepareRequest:
)
payload = json.loads(req.body)
assert payload["thinking"] == {"type": "enabled", "budget_tokens": 10000}
assert payload["thinking"] == {"type": "adaptive", "display": "summarized"}
assert payload["output_config"] == {"effort": "medium"}
assert payload["max_tokens"] == 1024
assert payload["temperature"] == 1
assert "temperature" not in payload
def test_with_tools(self, adapter, provider):
messages = [LLMMessage(role=Role.user, content="Hello")]