142 lines
5.0 KiB
Python
142 lines
5.0 KiB
Python
from pathlib import Path
|
|
import sys
|
|
from unittest.mock import patch
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
|
|
|
with patch(
|
|
"pydantic_settings.sources.providers.dotenv.DotEnvSettingsSource._read_env_files",
|
|
return_value={},
|
|
):
|
|
from aiprovider.provider_service import ProviderService
|
|
from aiprovider.schemas import SituationalAnalysisRequest
|
|
from app.api.v1.settings import _runtime_config_from_ai_payload
|
|
|
|
|
|
def test_custom_openai_gateway_keeps_its_configured_protocol():
|
|
config = _runtime_config_from_ai_payload(
|
|
{
|
|
"default_provider": "openai",
|
|
"providers": {
|
|
"openai": {
|
|
"base_url": "https://gateway.test/v1",
|
|
"provider_api": "openai-completions",
|
|
"model": "gpt-6-astra",
|
|
},
|
|
},
|
|
}
|
|
)["llm_config"]
|
|
service = ProviderService({**config, "api_key": "test-key"})
|
|
assert service._resolve_model_provider_api("gpt-6-astra") == "openai-completions"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize(
|
|
"model,path",
|
|
[("minimax-m3", "/messages"), ("qwen3.8-max", "/messages"), ("gpt-5.6-luna", "/responses")],
|
|
)
|
|
async def test_runtime_model_routes_use_current_protocols(monkeypatch, model, path):
|
|
llm = _runtime_config_from_ai_payload(
|
|
{
|
|
"default_provider": "opencode-go",
|
|
"providers": {
|
|
"opencode-go": {
|
|
"model": model,
|
|
"api_key": "test-key",
|
|
"model_provider_apis": {model: "openai-completions"},
|
|
}
|
|
},
|
|
}
|
|
)["llm_config"]
|
|
service = ProviderService(llm)
|
|
seen = []
|
|
|
|
async def post(**request):
|
|
seen.append(request)
|
|
assert request["path"] == path
|
|
assert request["request_body"]["model"] == model
|
|
if path == "/responses":
|
|
assert request["request_body"]["store"] is False
|
|
assert "max_tokens" not in request["request_body"]
|
|
return {
|
|
"output": [
|
|
{"type": "reasoning", "summary": [{"text": "reason"}]},
|
|
{"type": "message", "content": [{"type": "output_text", "text": "OK"}]},
|
|
]
|
|
}
|
|
return {"content": [{"type": "text", "text": "OK"}]}
|
|
|
|
monkeypatch.setattr(service, "_post", post)
|
|
result = await service.analyze(SituationalAnalysisRequest(title="test", objective="reply OK"))
|
|
assert len(seen) == 1
|
|
assert result.content == "OK"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_minimax_messages_url_accepts_both_documented_base_forms(monkeypatch):
|
|
seen = []
|
|
client_type = httpx.AsyncClient
|
|
|
|
def handle(request):
|
|
seen.append(str(request.url))
|
|
return httpx.Response(200, json={"content": [{"type": "text", "text": "OK"}]})
|
|
|
|
transport = httpx.MockTransport(handle)
|
|
monkeypatch.setattr(httpx, "AsyncClient", lambda **kw: client_type(transport=transport, **kw))
|
|
for base in ["https://api.minimaxi.com/anthropic", "https://api.minimaxi.com/anthropic/v1"]:
|
|
service = ProviderService(
|
|
{
|
|
"provider": "minimax",
|
|
"provider_api": "anthropic-messages",
|
|
"base_url": base,
|
|
"api_key": "test-key",
|
|
"model": "MiniMax-M3",
|
|
}
|
|
)
|
|
result = await service.analyze(
|
|
SituationalAnalysisRequest(title="test", objective="reply OK")
|
|
)
|
|
assert result.content == "OK"
|
|
assert seen == ["https://api.minimaxi.com/anthropic/v1/messages"] * 2
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_m3_playground_thinking_and_opencode_session_headers(monkeypatch):
|
|
seen = []
|
|
client_type = httpx.AsyncClient
|
|
|
|
def handle(request):
|
|
import json
|
|
|
|
seen.append(request)
|
|
assert json.loads(request.content)["thinking"] == {"type": "adaptive"}
|
|
assert request.headers["user-agent"] == "Planet/1.0"
|
|
return httpx.Response(200, json={"content": [{"type": "text", "text": "OK"}]})
|
|
|
|
transport = httpx.MockTransport(handle)
|
|
monkeypatch.setattr(httpx, "AsyncClient", lambda **kw: client_type(transport=transport, **kw))
|
|
for session_id in ["conversation-one", "conversation-one", "conversation-two"]:
|
|
service = ProviderService(
|
|
{
|
|
"provider": "opencode-go",
|
|
"provider_api": "anthropic-messages",
|
|
"base_url": "https://opencode.ai/zen/go/v1",
|
|
"api_key": "test-key",
|
|
"model": "minimax-m3",
|
|
}
|
|
)
|
|
await service.analyze(
|
|
SituationalAnalysisRequest(
|
|
title="test",
|
|
objective="reply OK",
|
|
thinking={"type": "enabled"},
|
|
context={"session_id": session_id},
|
|
)
|
|
)
|
|
session_headers = [request.headers["x-opencode-session"] for request in seen]
|
|
assert session_headers[0] == session_headers[1]
|
|
assert session_headers[0] != session_headers[2]
|