feat: add Chinese UI, Responses models, and mirrored Windows setup
CI / Python 3.12 / ubuntu-latest (push) Canceled after 0s
CI / Python 3.12 / windows-latest (push) Canceled after 0s
CI / Frontend tests and production build (push) Canceled after 0s
CI / Build and smoke-test Python packages (push) Canceled after 0s

Localize the web console and persist custom model and capability settings.
Use OpenAI Responses exclusively and move runtime limits into environment configuration.
Bootstrap uv and the virtual environment on Windows, support optional China mirrors,
and package source distributions without environments, build output, or credentials.

Update regression tests and repository quality checks for the new behavior.
This commit is contained in:
chenmingxuan committed 2026-09-22 19:16:17 +08:00
1 parent 371aa6df56
commit 2ddec53954
183 files changed
+3427 -11857

No files matched your search

@@ -26,11 +26,11 @@ from artemis.core.diagnostics.schema import (
class LLMCredentialsProbe(BaseProbe):
"""Probe verifying Gemini and multi-provider multimodal LLM credentials."""
"""Readiness depends on an OpenAI credential, never merely a base URL."""
@property
def probe_id(self) -> str:
return "gemini_api_key"
return "openai_api_key"
@property
def category(self) -> ProbeCategory:
@@ -40,192 +40,38 @@ class LLMCredentialsProbe(BaseProbe):
def is_blocker(self) -> bool:
return True
def _mask_key(self, key_str: str) -> str:
"""Helper to safely mask an API credential for display."""
if len(key_str) > 10:
return f"{key_str[:6]}...{key_str[-4:]}"
return "***"
async def probe(self) -> ProbeResult:
import os
from artemis.config.settings import is_placeholder_key
gemini_key = settings.get_api_key("google")
openai_key = settings.get_api_key("openai")
claude_key = settings.get_api_key("anthropic")
openrouter_key = settings.get_api_key("openrouter")
xai_key = settings.get_api_key("xai")
ocr_key = settings.get_api_key("ocr")
configured_providers: list[dict[str, Any]] = []
api_keys_map: dict[str, str] = {}
if gemini_key and not is_placeholder_key(gemini_key):
g_val = gemini_key.get_secret_value()
configured_providers.append(
{
"provider": "google",
"label": "Gemini",
"masked": self._mask_key(g_val),
"raw_key": g_val,
"key": g_val,
}
)
api_keys_map["google"] = g_val
api_keys_map["gemini"] = g_val
if openai_key and not is_placeholder_key(openai_key):
o_val = openai_key.get_secret_value()
configured_providers.append(
key = settings.get_api_key("openai")
configured = bool(key)
providers = (
[
{
"provider": "openai",
"label": "ChatGPT",
"masked": self._mask_key(o_val),
"raw_key": o_val,
"key": o_val,
"label": "OpenAI Responses",
"masked": "****" + key.get_secret_value()[-4:],
}
)
api_keys_map["openai"] = o_val
if claude_key and not is_placeholder_key(claude_key):
c_val = claude_key.get_secret_value()
configured_providers.append(
{
"provider": "anthropic",
"label": "Claude",
"masked": self._mask_key(c_val),
"raw_key": c_val,
"key": c_val,
}
)
api_keys_map["anthropic"] = c_val
if openrouter_key and not is_placeholder_key(openrouter_key):
or_val = openrouter_key.get_secret_value()
configured_providers.append(
{
"provider": "openrouter",
"label": "OpenRouter",
"masked": self._mask_key(or_val),
"raw_key": or_val,
"key": or_val,
}
)
api_keys_map["openrouter"] = or_val
if xai_key and not is_placeholder_key(xai_key):
x_val = xai_key.get_secret_value()
configured_providers.append(
{
"provider": "xai",
"label": "xAI (Grok)",
"masked": self._mask_key(x_val),
"raw_key": x_val,
"key": x_val,
}
)
api_keys_map["xai"] = x_val
# Detect any custom model endpoints or environment variables defined in files
for env_var, label, prov_id in [
("DEEPSEEK_API_KEY", "DeepSeek", "deepseek"),
("GROQ_API_KEY", "Groq", "groq"),
("OPENAI_BASE_URL", "Custom OpenAI Endpoint", "custom"),
("OLLAMA_BASE_URL", "Local Ollama", "ollama"),
("VLLM_BASE_URL", "vLLM Endpoint", "vllm"),
("VERTEX_AI_PROJECT", "Google Cloud Vertex AI", "vertexai"),
]:
val = os.environ.get(env_var)
if val and val.strip() and not is_placeholder_key(val.strip()):
configured_providers.append(
{
"provider": prov_id,
"label": label,
"masked": self._mask_key(val.strip()),
"raw_key": val.strip(),
"key": val.strip(),
}
)
api_keys_map[prov_id] = val.strip()
if ocr_key and not is_placeholder_key(ocr_key):
api_keys_map["ocr"] = ocr_key.get_secret_value()
current_active_key = (
gemini_key.get_secret_value()
if gemini_key
else (configured_providers[0]["key"] if configured_providers else "")
]
if key
else []
)
metadata = {
"configured_count": len(configured_providers),
"providers": configured_providers,
"has_ocr_key": ocr_key is not None,
"current_key": current_active_key,
"current_gemini_key": gemini_key.get_secret_value() if gemini_key else "",
"api_keys": api_keys_map,
}
# Case 1: Gemini API Key configured (Standard / Recommended)
if gemini_key:
masked = self._mask_key(gemini_key.get_secret_value())
return ProbeResult(
id=self.probe_id,
category=self.category,
title="Multimodal LLM API Key",
status=ProbeStatus.PASS,
is_blocker=self.is_blocker,
summary="Active (Gemini)",
description=f"Gemini multimodal API credential is active ({masked}) and ready for vision and reasoning.",
metadata=metadata,
actions=[
ProbeAction(
action_type="hint",
label="Provider Active",
payload="Gemini 2.5 Flash / Pro Multimodal Engine is enabled.",
)
],
)
# Case 2: Other LLM provider configured
if configured_providers:
first_p = configured_providers[0]
return ProbeResult(
id=self.probe_id,
category=self.category,
title="Multimodal LLM API Key",
status=ProbeStatus.PASS,
is_blocker=self.is_blocker,
summary=f"Active ({first_p['label']})",
description=f"{first_p['label']} multimodal API credential is active ({first_p['masked']}).",
metadata=metadata,
actions=[
ProbeAction(
action_type="hint",
label="Provider Active",
payload=f"{first_p['label']} multimodal vision endpoint is active.",
)
],
)
# Case 3: No LLM key configured
return ProbeResult(
id=self.probe_id,
category=self.category,
title="Multimodal LLM API Key",
status=ProbeStatus.FAIL,
is_blocker=self.is_blocker,
summary="Key Missing",
description="No Multimodal LLM credential (e.g. GEMINI_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY) found in environment or .env file.",
metadata=metadata,
actions=[
ProbeAction(
action_type="command",
label="Run Artemis Init",
payload="artemis init",
),
ProbeAction(
action_type="link",
label="Get Google AI Studio Key",
payload="https://aistudio.google.com/app/apikey",
),
],
title="OpenAI API 密钥",
status=ProbeStatus.PASS if configured else ProbeStatus.FAIL,
is_blocker=True,
summary="已配置 OpenAI Responses" if configured else "缺少 API 密钥",
description="模型统一通过 OpenAI Responses 接口调用。"
if configured
else "请在环境变量或 .env 中设置 OPENAI_API_KEY。",
metadata={
"configured_count": len(providers),
"providers": providers,
"has_ocr_key": bool(settings.get_api_key("ocr")),
},
actions=[]
if configured
else [ProbeAction(action_type="command", label="初始化配置", payload="artemis init")],
)
@@ -267,7 +113,7 @@ class VisionOCRProbe(BaseProbe):
is_blocker=False,
summary="Active & Configured",
description=f"Google Cloud Vision OCR ({masked}) is active for image text recognition.",
metadata={"configured": True, "masked_key": masked, "key": val, "raw_key": val},
metadata={"configured": True, "masked_key": masked},
actions=[
ProbeAction(
action_type="hint",
@@ -17,7 +17,7 @@
import platform
import sys
from artemis.config import parse_llm_config
from artemis.config import parse_llm_config, settings
from artemis.core.diagnostics.probes.base import BaseProbe
from artemis.core.diagnostics.schema import (
ProbeAction,
@@ -67,7 +67,7 @@ class PythonRuntimeProbe(BaseProbe):
title="Python Runtime Environment",
status=ProbeStatus.PASS,
is_blocker=self.is_blocker,
summary=f"Python {py_ver_str} Ready",
summary=f"Python {py_ver_str} 已就绪",
description=f"Python {py_ver_str} ({arch}, 64-bit) detected at {executable}. Satisfies requirement (>= 3.12).",
metadata=metadata,
actions=[
@@ -121,7 +121,7 @@ class SystemConfigProbe(BaseProbe):
async def probe(self) -> ProbeResult:
try:
cfg = parse_llm_config()
planner_model = getattr(getattr(cfg, "planner", None), "model", "Gemini 2.5 Flash")
planner_model = getattr(getattr(cfg, "planner", None), "model", settings.OPENAI_MODEL)
metadata = {
"valid": True,
"config_file": "config/artemis.jsonc",
@@ -133,7 +133,7 @@ class SystemConfigProbe(BaseProbe):
title="Artemis System Configuration",
status=ProbeStatus.PASS,
is_blocker=self.is_blocker,
summary="Config Valid",
summary="配置有效",
description=f"System configuration loaded and validated (Planner model: {planner_model}).",
metadata=metadata,
actions=[
@@ -72,7 +72,7 @@ class ToolchainProbe(BaseProbe):
title="Video Recording Toolchain",
status=ProbeStatus.PASS,
is_blocker=self.is_blocker,
summary="Ready (FFmpeg + scrcpy)",
summary="录屏工具已就绪(FFmpeg + scrcpy)",
description=f"FFmpeg ({ffmpeg_path}) and scrcpy ({scrcpy_path}) are available. Live stream and high-speed video replays are active.",
metadata=metadata,
actions=[
@@ -132,7 +132,7 @@ class ToolchainProbe(BaseProbe):
title="Video Recording Toolchain",
status=ProbeStatus.FAIL,
is_blocker=self.is_blocker,
summary=f"Missing {missing_str}",
summary=f"缺少 {missing_str}",
description=f"Video toolchain is required for screen streaming and test replay recording. Missing: {missing_str}.",
metadata=metadata,
actions=actions,
+1 -1
View File
@@ -39,7 +39,7 @@ CHECK_ORDER: dict[str, int] = {
"python_runtime": 0,
"system_config": 1,
"integration_host": 2,
"gemini_api_key": 3,
"openai_api_key": 3,
"android_adb": 4,
"toolchain": 5,
"vision_ocr_key": 6,
+1 -1
View File
@@ -78,7 +78,7 @@ class ProbeResult(BaseModel):
"""Outcome of a single readiness probe check."""
id: str = Field(
description="Unique identifier for the probe (e.g. 'android_adb', 'gemini_api_key')"
description="Unique identifier for the probe (e.g. 'android_adb', 'openai_api_key')"
)
category: ProbeCategory = Field(description="Category of the probe")
title: str = Field(description="Human-readable title (e.g. 'Device / Emulator Connected')")