feat: integrate calibration extension and self-repair modules

This commit is contained in:
vee
2026-08-07 23:39:45 +08:00
parent 156b10fda1
commit 3bceb0d5a1
41 changed files with 21310 additions and 314 deletions
+124 -12
View File
@@ -14,6 +14,10 @@ from unittest.mock import patch
from cognitive_agent.auth import AuthConfig, AuthRuntime, hash_password
from cognitive_agent.application.seat_service import REPOSITORY_ROOT, SeatDemoService
from cognitive_agent.application.self_extension import (
SelfExtensionService,
SimulationGateway,
)
from cognitive_agent.infrastructure.llm.openai_responses import OpenAIIntentError
from cognitive_agent.infrastructure.can.access import HardwareAccessController
from cognitive_agent.server import SeatDemoHandler
@@ -111,20 +115,32 @@ class SeatWebApiTests(unittest.TestCase):
def test_static_console_and_runtime_endpoint(self) -> None:
with self.opener.open(f"{self.base_url}/", timeout=3) as response:
html = response.read().decode("utf-8")
with self.opener.open(f"{self.base_url}/app.js?v=seat-hil-42", timeout=3) as response:
with self.opener.open(f"{self.base_url}/app.js?v=seat-hil-43", timeout=3) as response:
app_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/gesture-control.js?v=android-pad-5", timeout=3
f"{self.base_url}/gesture-control.js?v=android-pad-6", timeout=3
) as response:
gesture_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/console-v2.js?v=desktop-refactor-16", timeout=3
f"{self.base_url}/console-v2.js?v=desktop-refactor-28", timeout=3
) as response:
console_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/console-v2.css?v=desktop-refactor-56", timeout=3
f"{self.base_url}/console-v2.css?v=desktop-refactor-68", timeout=3
) as response:
console_styles = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/self-extension.js?v=extension-6", timeout=3
) as response:
extension_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/self-extension.css?v=extension-9", timeout=3
) as response:
extension_styles = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/api/extension/health", timeout=3
) as response:
extension_health = json.loads(response.read().decode("utf-8"))
with self.opener.open(f"{self.base_url}/api/runtime", timeout=3) as response:
runtime = json.loads(response.read().decode("utf-8"))
@@ -134,19 +150,40 @@ class SeatWebApiTests(unittest.TestCase):
self.assertIn("整车孪生界面", html)
self.assertIn("<strong>阅读灯</strong>", html)
self.assertNotIn("透明车体 · 实体设备", html)
self.assertIn('src="/app.js?v=seat-hil-42"', html)
self.assertIn('src="/gesture-control.js?v=android-pad-5"', html)
self.assertIn('src="/app.js?v=seat-hil-43"', html)
self.assertIn('src="/gesture-control.js?v=android-pad-6"', html)
self.assertNotIn('class="vehicle-system-hud"', html)
self.assertIn('src="/console-v2.js?v=desktop-refactor-16"', html)
self.assertIn('href="/console-v2.css?v=desktop-refactor-56"', html)
self.assertIn('src="/console-v2.js?v=desktop-refactor-28"', html)
self.assertIn('href="/console-v2.css?v=desktop-refactor-68"', html)
self.assertIn('src="/self-extension.js?v=extension-6"', html)
self.assertIn('href="/self-extension.css?v=extension-9"', html)
self.assertNotIn("滚动查看更多", html)
self.assertIn('aria-label="执行车舱控制指令"', html)
self.assertIn('sessionStorage.getItem("cognitive-agent.demo-role")', console_script)
self.assertIn('id="v2SidebarToggle"', console_script)
self.assertIn('class="field-label">手势模型</span>', console_script)
self.assertIn('id = "v2ModuleSwitcher"', console_script)
self.assertIn('label: "自编排", available: true', console_script)
self.assertIn('id: "self-calibration"', console_script)
self.assertIn('label: "自标定"', console_script)
self.assertIn("adminOnly: true", console_script)
self.assertIn(
"$('.v2-module-tab[data-module=\"self-calibration\"]')",
console_script,
)
self.assertIn('label: "自扩展", available: true', console_script)
self.assertIn('aria-label="自扩展面向所有登录用户"', console_script)
self.assertIn('<span>Hi,</span><strong>user</strong>', console_script)
self.assertIn('id: "self-repair"', console_script)
self.assertIn('label: "自修复"', console_script)
self.assertIn('roleSelect.disabled = ui.activeModule === "self-repair"', console_script)
self.assertNotIn('label: "自诊断"', console_script)
self.assertIn('<small>手势模型</small>', console_script)
self.assertIn('id="v2GestureModelValue">MediaPipe GR</strong>', console_script)
self.assertIn('id="v2GestureModelNote">Tasks Vision · 0.10.14</small>', console_script)
self.assertIn('cameraStage.append(cameraToggle)', console_script)
self.assertIn('<span class="v2-field-caption">配置信息</span>', console_script)
self.assertIn('state.id = "v2VehicleState"', console_script)
self.assertIn('fetch("/api/extension/health"', console_script)
self.assertIn('actionRail.append(cameraToggle)', console_script)
self.assertIn("function enhanceConfiguredDropdowns()", console_script)
self.assertIn("function updateModeEdgeHints()", console_script)
self.assertIn('classList.toggle("v2-twin-active", definition.index === 0)', console_script)
@@ -154,10 +191,23 @@ class SeatWebApiTests(unittest.TestCase):
self.assertIn('userTargetText.textContent = "真实台架尚未就绪"', console_script)
self.assertIn('grid-template-columns: clamp(245px, 18.5vw, 310px)', console_styles)
self.assertIn('.v2-control-switch {', console_styles)
self.assertIn('.v2-module-switcher {', console_styles)
self.assertIn('grid-template-columns: repeat(4, minmax(0, 1fr))', console_styles)
self.assertIn('margin-inline: calc(0px - var(--v2-main-pad))', console_styles)
self.assertIn('background: color-mix(in srgb, var(--v2-accent) 30%, var(--v2-accent-soft))', console_styles)
self.assertIn('width: clamp(48px, 45%, 72px)', console_styles)
self.assertIn('font-weight: 800', console_styles)
self.assertIn('width: clamp(300px, 28vw, 360px)', console_styles)
self.assertIn('white-space: nowrap', console_styles)
self.assertIn('.v2-gesture-model-field', console_styles)
self.assertIn('.v2-inline-gesture .v2-camera-toggle', console_styles)
self.assertIn('[data-demo-role="user"] .v2-inline-gesture .gesture-actions', console_styles)
self.assertIn('.v2-inline-gesture .v2-gesture-action-rail', console_styles)
self.assertIn('grid-template-rows: 42px 10px 42px', console_styles)
self.assertIn('background: var(--v2-accent);', console_styles)
self.assertIn('[data-demo-role="user"] .v2-inline-gesture #gestureArmButton svg', console_styles)
self.assertIn('.v2-inline-gesture #gestureStopButton', console_styles)
self.assertIn('.v2-inline-gesture .v2-gesture-result-stack', console_styles)
self.assertIn('.v2-inline-gesture .v2-gesture-execution-slot', console_styles)
self.assertIn('grid-template-columns: 1fr;', console_styles)
self.assertIn('.v2-page-rail', console_styles)
self.assertIn('.v2-dropdown-menu', console_styles)
@@ -171,8 +221,12 @@ class SeatWebApiTests(unittest.TestCase):
self.assertIn('.joint-twin-shell .domain-readouts', console_styles)
self.assertIn('grid-template-columns: repeat(2, minmax(0, 1fr))', console_styles)
self.assertIn('.v2-config-section > .v2-field-caption', console_styles)
self.assertIn('.console-v2 .v2-config-card {', console_styles)
self.assertIn('.console-v2.v2-sidebar-collapsed .workspace', console_styles)
self.assertIn('id="hardwareAccessField"', html)
self.assertNotIn('id="hardwareAccessField"', html)
self.assertNotIn('id="hardwareClientLabel"', html)
self.assertNotIn('id="requestHardwareAccess"', html)
self.assertNotIn('id="releaseHardwareAccess"', html)
self.assertIn('const dynamicModeOrder = ["rocking_horse", "dynamic_cradle"]', app_script)
self.assertIn('divider.className = "mode-group-divider"', app_script)
self.assertIn("function extractReferenceWindowPanes", app_script)
@@ -189,6 +243,37 @@ class SeatWebApiTests(unittest.TestCase):
self.assertIn("function styleReferencePassiveRearExterior", app_script)
self.assertIn('twinRole: "reference_passive_rear_bumper"', app_script)
self.assertIn('"cognitive-agent:demo-role-change"', console_script)
self.assertIn('resultStack.id = "v2GestureResultStack"', console_script)
self.assertIn('executionSlot.id = "v2GestureExecutionSlot"', console_script)
self.assertIn('statusTarget.append(requestStatus)', console_script)
self.assertIn('root.id = "v2SelfExtension"', extension_script)
self.assertIn('data-extension-mode="study"', extension_script)
self.assertIn('data-extension-mode="control"', extension_script)
self.assertIn('外设玩具能力一览与学习', extension_script)
self.assertIn('说一句,联动外设玩具与车端设备', extension_script)
self.assertIn('id="extensionExecuteButton"', extension_script)
self.assertIn('data-lucide="play"', extension_script)
self.assertNotIn('id="extensionControlHealth"', extension_script)
self.assertIn('data-extension-connected="${Boolean(selected)}"', extension_script)
self.assertIn('<small>红外学习器</small>', extension_script)
self.assertIn('id="extensionStudyHealthState"', extension_script)
self.assertIn('id="extensionVehicleState">CHECK</span>', extension_script)
self.assertIn('id="extensionResetButton"', extension_script)
self.assertNotIn('id="extensionConnectionButton"', extension_script)
self.assertNotIn('id="extensionStatusDialog"', extension_script)
self.assertIn('/api/extension/${path}', extension_script)
self.assertIn('[data-module="self-extension"]', extension_styles)
self.assertIn('[data-module="self-extension"] .v2-role-select', extension_styles)
self.assertIn('.v2-extension-composer .primary-action {', extension_styles)
self.assertIn('--v2-accent: #0e7773', extension_styles)
self.assertIn('.v2-sidebar-collapsed[data-module="self-extension"] .v2-extension-sidebar', extension_styles)
self.assertIn('.v2-extension-capability span {', extension_styles)
self.assertIn('.v2-extension-vehicle-card > div button {', extension_styles)
self.assertIn('.v2-extension-type-card[data-extension-connected="true"]', extension_styles)
self.assertIn('.v2-extension-type-card[data-extension-connected="false"]', extension_styles)
self.assertIn('grid-template-columns: repeat(3, minmax(0, 1fr))', extension_styles)
self.assertTrue(extension_health["success"])
self.assertIn(extension_health["transport"], {"tcp", "mqtt", "simulation"})
self.assertIn("function emphasizeReferenceFrontLampMeshes", app_script)
self.assertIn("function createReferenceFrontLampHighlights", app_script)
self.assertIn("referenceFrontLampMaterials", app_script)
@@ -204,6 +289,7 @@ class SeatWebApiTests(unittest.TestCase):
self.assertIn('case "OverconstrainedError":', gesture_script)
self.assertIn("function sendSimulatedGesture()", gesture_script)
self.assertIn('document.body.dataset.demoRole !== "admin"', gesture_script)
self.assertIn("function syncGestureDebugRole", gesture_script)
self.assertIn("HARDWARE_REQUEST_TIMEOUT_MS = 15 * 60 * 1000", app_script)
self.assertIn(
"requestTimeoutForExecutionMode(state.executionMode)", app_script
@@ -296,6 +382,32 @@ class SeatWebApiTests(unittest.TestCase):
all(item["target_scopes"] == ["passenger"] for item in seat_capabilities)
)
def test_self_extension_gateway_uses_unified_authenticated_service(self) -> None:
original_extension = SeatDemoHandler.extension
SeatDemoHandler.extension = SelfExtensionService(SimulationGateway())
try:
with self.opener.open(
f"{self.base_url}/api/extension/health", timeout=3
) as response:
health = json.loads(response.read().decode("utf-8"))
request = urllib.request.Request(
f"{self.base_url}/api/extension/gscu/emit",
method="POST",
headers={"Content-Type": "application/json"},
data=json.dumps({"slot": 9}).encode("utf-8"),
)
with self.opener.open(request, timeout=3) as response:
result = json.loads(response.read().decode("utf-8"))
finally:
SeatDemoHandler.extension = original_extension
self.assertTrue(health["success"])
self.assertEqual(health["transport"], "simulation")
self.assertTrue(health["connected"])
self.assertTrue(result["success"])
self.assertEqual(result["transport"], "simulation")
self.assertFalse(result["physical_state_confirmed"])
def test_post_request_returns_complete_dry_run(self) -> None:
request = urllib.request.Request(
f"{self.base_url}/api/requests",