feat: harden seat intent and expand HIL coverage

This commit is contained in:
vee
2026-08-02 05:20:38 +08:00
parent 4aded5c21d
commit 55d0d400cb
62 changed files with 53112 additions and 1748 deletions
+123
View File
@@ -95,6 +95,9 @@ class SeatWebApiTests(unittest.TestCase):
self.assertIn("/login", final_url)
self.assertIn("体验账号登录", login_html)
with unauthenticated.open(f"{self.base_url}/network.js", timeout=3) as response:
network_script = response.read().decode("utf-8")
self.assertIn("CognitiveAgentNetwork", network_script)
with self.assertRaises(urllib.error.HTTPError) as caught:
unauthenticated.open(f"{self.base_url}/api/runtime", timeout=3)
self.assertEqual(caught.exception.code, 401)
@@ -102,6 +105,8 @@ 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-7", timeout=3) as response:
app_script = 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"))
@@ -110,6 +115,11 @@ class SeatWebApiTests(unittest.TestCase):
self.assertIn('data-vehicle-model="byd-tang-2024-reference"', html)
self.assertIn("整车孪生界面", html)
self.assertIn("透明车体 · 实体设备", html)
self.assertIn('src="/app.js?v=seat-hil-7"', html)
self.assertIn("HARDWARE_REQUEST_TIMEOUT_MS = 15 * 60 * 1000", app_script)
self.assertIn(
"requestTimeoutForExecutionMode(state.executionMode)", app_script
)
self.assertIn("FBXLoader.js", html)
self.assertIn('data-seat-layout="five-seat"', html)
self.assertIn('data-active-seat="front-right"', html)
@@ -202,6 +212,119 @@ class SeatWebApiTests(unittest.TestCase):
self.assertEqual(result["vehicle"]["id"], "denza_n7")
self.assertEqual(result["actuator_state"]["passenger"]["ventilation"]["level"], 1)
def test_relative_backrest_phrase_uses_current_conversation_position(self) -> None:
conversation_id = "conv-e2e-relative-backrest"
for utterance in ("副驾靠背角度调到130度", "靠背向前移动10度"):
request = urllib.request.Request(
f"{self.base_url}/api/requests",
method="POST",
headers={"Content-Type": "application/json"},
data=json.dumps(
{
"utterance": utterance,
"provider": "local",
"conversation_id": conversation_id,
"vehicle_id": "denza_n7",
"execution_mode": "dry_run",
},
ensure_ascii=False,
).encode("utf-8"),
)
with self.opener.open(request, timeout=3) as response:
result = json.loads(response.read().decode("utf-8"))
self.assertEqual(result["status"], "succeeded")
operation = result["function_config"]["spec"]["operations"][0]
self.assertEqual(operation["capability"], "seat.set_backrest_recline")
self.assertEqual(operation["parameters"]["position_pct"], 36)
self.assertEqual(operation["parameters"]["angle_deg"], 120)
self.assertEqual(operation["motion"]["direction"], "decrease")
self.assertEqual(operation["motion"]["delta_angle_deg"], 10.0)
def test_timed_and_oversized_backrest_requests_use_endpoint_fallbacks(self) -> None:
conversation_id = "conv-e2e-timed-endpoint-fallbacks"
def submit(utterance: str) -> dict:
request = urllib.request.Request(
f"{self.base_url}/api/requests",
method="POST",
headers={"Content-Type": "application/json"},
data=json.dumps(
{
"utterance": utterance,
"provider": "local",
"conversation_id": conversation_id,
"vehicle_id": "denza_n7",
"execution_mode": "dry_run",
},
ensure_ascii=False,
).encode("utf-8"),
)
with self.opener.open(request, timeout=3) as response:
return json.loads(response.read().decode("utf-8"))
submit("副驾靠背归零")
timed = submit("靠背向后移动70秒")
self.assertEqual(timed["status"], "succeeded")
timed_operation = timed["function_config"]["spec"]["operations"][0]
self.assertEqual(timed_operation["parameters"]["position_pct"], 100)
self.assertEqual(timed_operation["motion"]["mode"], "timed")
self.assertEqual(timed_operation["motion"]["requested_duration_ms"], 70_000)
self.assertEqual(timed_operation["motion"]["applied_duration_ms"], 30_000)
self.assertTrue(timed_operation["motion"]["duration_clamped"])
self.assertIn("最大允许时长为30秒", "\n".join(timed["decision_summary"]))
submit("副驾靠背角度调到130度")
overflow = submit("靠背向后移动70度")
self.assertEqual(overflow["status"], "succeeded")
overflow_operation = overflow["function_config"]["spec"]["operations"][0]
self.assertEqual(overflow_operation["parameters"]["position_pct"], 100)
self.assertEqual(overflow_operation["parameters"]["angle_deg"], 163)
self.assertTrue(overflow_operation["motion"]["range_clamped"])
self.assertEqual(
overflow_operation["motion"]["requested_delta_angle_deg"], 70
)
self.assertIn("备用目标", "\n".join(overflow["decision_summary"]))
def test_open_zero_gravity_phrase_matches_complete_mode(self) -> None:
request = urllib.request.Request(
f"{self.base_url}/api/requests",
method="POST",
headers={"Content-Type": "application/json"},
data=json.dumps(
{
"utterance": "打开零重力模式",
"provider": "local",
"conversation_id": "conv-e2e-open-zero-gravity",
"vehicle_id": "denza_n7",
"execution_mode": "dry_run",
},
ensure_ascii=False,
).encode("utf-8"),
)
with self.opener.open(request, timeout=3) as response:
result = json.loads(response.read().decode("utf-8"))
self.assertEqual(result["status"], "succeeded")
self.assertIn("zero_gravity", {item["id"] for item in result["matched_modes"]})
operations = result["function_config"]["spec"]["operations"]
self.assertEqual(len(operations), 4)
self.assertEqual(
{
operation["capability"]: operation["parameters"]["position_pct"]
for operation in operations
},
{
"seat.set_longitudinal_position": 100,
"seat.set_cushion_tilt": 100,
"seat.set_backrest_recline": 81,
"seat.set_legrest_height": 94,
},
)
self.assertEqual(result["execution_report"]["spec"]["mode"], "dry_run")
def test_hardware_state_endpoint_returns_physical_passenger_snapshot(self) -> None:
synchronized = {
"status": "succeeded",