Files
Aether/tests/services/test_vertex_ai_transport.py
fawney19 6984984c22 feat(provider): 重构模型测试对话框,加固 Vertex AI 传输层
模型测试:
- 将消息输入替换为完整 JSON 请求体编辑器,支持格式化和校验
- 新增端点选择面板,测试前可选择目标端点
- 新增调试检查器,可查看每次尝试的请求/响应头和体
- 结果视图改用 HorizontalRequestTimeline 组件展示请求追踪
- endpoint_checker 返回完整调试数据,通过 candidate extra_data 持久化

Vertex AI:
- 改进上下文检测逻辑,不再仅依赖 provider_type,支持从 base_url 推断
- Service Account 密钥现支持自动拉取模型(使用 auth_config 而非 api_key)
- 移除 Gemini Developer API 回退,API Key 仅走 Express 模式
- 端点表单为 Vertex AI 显示格式特定的默认路径模板
- 密钥格式校验仅在 auth_type/api_formats 变更时执行

其他:
- 禁用 ClaudeCode 提供商类型创建入口
- Dialog 组件新增 closeOnBackdrop 属性
2026-03-19 23:52:17 +08:00

95 lines
3.0 KiB
Python

from __future__ import annotations
from types import SimpleNamespace
from urllib.parse import parse_qs, urlparse
import pytest
from src.core.exceptions import InvalidRequestException
from src.services.provider.adapters.vertex_ai.transport import build_vertex_ai_url
def test_build_vertex_ai_url_uses_express_mode_for_gemini_api_key(
monkeypatch: pytest.MonkeyPatch,
) -> None:
key = SimpleNamespace(auth_type="api_key", api_key="enc-key")
from src.core.crypto import crypto_service
monkeypatch.setattr(crypto_service, "decrypt", lambda value: "test-key")
url = build_vertex_ai_url(
SimpleNamespace(),
is_stream=True,
effective_query_params={"foo": "bar"},
path_params={"model": "gemini-2.5-pro"},
key=key,
)
parsed = urlparse(url)
assert parsed.scheme == "https"
assert parsed.netloc == "aiplatform.googleapis.com"
assert parsed.path == "/v1/publishers/google/models/gemini-2.5-pro:streamGenerateContent"
assert parse_qs(parsed.query) == {
"foo": ["bar"],
"key": ["test-key"],
"alt": ["sse"],
}
def test_build_vertex_ai_url_uses_standard_vertex_path_for_gemini_service_account() -> None:
key = SimpleNamespace(auth_type="service_account")
url = build_vertex_ai_url(
SimpleNamespace(),
is_stream=False,
effective_query_params={"foo": "bar", "beta": "1"},
path_params={"model": "gemini-3.1-pro-preview"},
key=key,
decrypted_auth_config={"project_id": "demo-project", "region": "global"},
)
parsed = urlparse(url)
assert parsed.scheme == "https"
assert parsed.netloc == "aiplatform.googleapis.com"
assert (
parsed.path
== "/v1/projects/demo-project/locations/global/publishers/google/models/gemini-3.1-pro-preview:generateContent"
)
assert parse_qs(parsed.query) == {"foo": ["bar"]}
def test_build_vertex_ai_url_rejects_claude_api_key() -> None:
key = SimpleNamespace(auth_type="api_key")
with pytest.raises(InvalidRequestException, match="Claude 模型"):
build_vertex_ai_url(
SimpleNamespace(),
is_stream=False,
effective_query_params={},
path_params={"model": "claude-3-7-sonnet@20250219"},
key=key,
)
def test_build_vertex_ai_url_uses_standard_vertex_path_for_claude_service_account() -> None:
key = SimpleNamespace(auth_type="service_account")
url = build_vertex_ai_url(
SimpleNamespace(),
is_stream=False,
effective_query_params={"foo": "bar", "beta": "1"},
path_params={"model": "claude-3-7-sonnet@20250219"},
key=key,
decrypted_auth_config={"project_id": "demo-project", "region": "global"},
)
parsed = urlparse(url)
assert parsed.scheme == "https"
assert parsed.netloc == "aiplatform.googleapis.com"
assert (
parsed.path
== "/v1/projects/demo-project/locations/global/publishers/anthropic/models/claude-3-7-sonnet@20250219:rawPredict"
)
assert parse_qs(parsed.query) == {"foo": ["bar"]}