feat: synchronize CH1 vehicle control and feedback

This commit is contained in:
vee
2026-08-11 10:42:13 +08:00
parent 3701192a11
commit 32379a1573
50 changed files with 13636 additions and 736 deletions
@@ -177,7 +177,7 @@ class SeatServiceIntegrationTests(unittest.TestCase):
route = next(event for event in result["trace_events"] if event["stage"] == "domain_route")
self.assertEqual(route["details"]["domains"], ["climate"])
def test_openai_output_is_not_rewritten_by_local_semantic_planner(self) -> None:
def test_openai_unscoped_passenger_target_is_rewritten_to_driver_ch1(self) -> None:
model_output = {
"detected_domains": ["seat"],
"requests": [
@@ -199,26 +199,31 @@ class SeatServiceIntegrationTests(unittest.TestCase):
with patch.object(self.service.openai, "interpret", return_value=model_output) as interpret:
parsed, provider, notice = self.service._interpret(
"车上太闷了", "openai", context
"关闭座椅通风", "openai", context
)
self.assertEqual(parsed["decision_summary"], ["model-owned-plan"])
self.assertEqual(parsed["model_requests"], model_output["requests"])
self.assertEqual(parsed["actions"], [])
self.assertEqual(
parsed["actions"],
parsed["deferred_requests"],
[
{
"target": "passenger",
"function": "ventilation",
"state": "off",
"requested_level": None,
"domain": "seat",
"capability": "seat.set_driver_ventilation_native",
"target_scope": "driver",
"desired_change": "deactivate",
"requested_value": "off",
"parameters": {"state": "off"},
"reason": "model-owned-plan",
"execution_backend": "native_can",
}
],
)
self.assertEqual(provider, f"openai:{self.service.openai.model}")
self.assertIsNone(notice)
interpret.assert_called_once_with(
"车上太闷了", context, self.service.capability_context
"关闭座椅通风", context, self.service.capability_context
)
def test_explicit_gpt_failure_falls_back_to_local_rules(self) -> None:
@@ -680,7 +685,7 @@ class SeatServiceIntegrationTests(unittest.TestCase):
conversation_id,
)
second = self.service.process(
"靠背再向后一点", "openai", conversation_id
"副驾靠背再向后一点", "openai", conversation_id
)
saved = self.service.process(
"将当前状态保存为零重力模式", "openai", conversation_id
@@ -767,24 +772,35 @@ class SeatServiceIntegrationTests(unittest.TestCase):
apply_context = interpret.call_args_list[4].args[1]
self.assertEqual(apply_context["presets"][0]["name"], "零重力模式")
def test_missing_target_defaults_to_passenger(self) -> None:
def test_missing_target_defaults_to_driver_ch1(self) -> None:
result = self.service.process("打开座椅通风", provider="local")
self.assertEqual(result["status"], "succeeded")
operation = result["function_config"]["spec"]["operations"][0]
self.assertEqual(operation["target"]["instance"], "passenger")
self.assertEqual(operation["target"]["zone"], "driver")
self.assertEqual(
operation["capability"], "seat.set_driver_ventilation_native"
)
self.assertEqual(
result["command_plan"]["spec"]["commands"][0]["bus"],
"body_can",
)
def test_explicit_driver_target_is_rejected(self) -> None:
def test_explicit_driver_target_uses_ch1_native_can(self) -> None:
result = self.service.process("打开主驾座椅通风", provider="local")
self.assertEqual(result["status"], "needs_confirmation")
self.assertIsNone(result["function_config"])
questions = [
item["question"] for item in result["intent_ir"]["spec"]["ambiguities"]
]
self.assertTrue(any("仅控制副驾" in question for question in questions))
self.assertEqual(result["status"], "succeeded")
operation = result["function_config"]["spec"]["operations"][0]
self.assertEqual(operation["target"]["zone"], "driver")
self.assertEqual(
operation["capability"], "seat.set_driver_ventilation_native"
)
command = result["command_plan"]["spec"]["commands"][0]
self.assertEqual(command["bus"], "body_can")
self.assertEqual(command["signals"]["frame_id"], "0x431")
self.assertEqual(command["signals"]["feedback_ids"], "0x4FA")
def test_model_driver_target_is_rejected(self) -> None:
def test_model_driver_target_is_replaced_by_ch1_native_can(self) -> None:
model_output = {
"detected_domains": ["seat"],
"requests": [
@@ -808,12 +824,13 @@ class SeatServiceIntegrationTests(unittest.TestCase):
"打开主驾座椅通风", "openai", "conv-driver-rejected"
)
self.assertEqual(result["status"], "needs_confirmation")
self.assertIsNone(result["function_config"])
questions = [
item["question"] for item in result["intent_ir"]["spec"]["ambiguities"]
]
self.assertTrue(any("仅控制副驾" in question for question in questions))
self.assertEqual(result["status"], "succeeded")
operation = result["function_config"]["spec"]["operations"][0]
self.assertEqual(operation["target"]["zone"], "driver")
self.assertEqual(
operation["capability"], "seat.set_driver_ventilation_native"
)
self.assertFalse(result["deferred_requests"])
if __name__ == "__main__":
+3 -3
View File
@@ -476,7 +476,7 @@ class ProtocolSignatureFakeBus:
self.received: deque[CanFrame] = deque()
self.closed = False
if signature:
self.received.append(CanFrame(0x301, bytes.fromhex("10 00 00 00 00 00 F0 D0")))
self.received.append(CanFrame(0x301, bytes.fromhex("10 00 00 00 00 00 F0 F0")))
for motor in range(4):
self.received.append(
CanFrame(0x302, bytes([motor, 0, 0x08, 0, 0, 0, 0, 0]))
@@ -1684,7 +1684,7 @@ class T2GHardwareTests(unittest.TestCase):
self.assertIs(prepared, bus)
self.assertFalse(telemetry["programmed_this_request"])
self.assertEqual(telemetry["firmware_revision"], 13)
self.assertEqual(telemetry["firmware_revision"], 15)
self.assertEqual(bus.sent, [])
self.assertEqual(telemetry["max_hall_counts"], [480, 374, 917, 647])
self.assertFalse(bus.closed)
@@ -1755,7 +1755,7 @@ class T2GHardwareTests(unittest.TestCase):
guard.prepare_bus()
message = str(raised.exception)
self.assertIn("firmware_revision=0 (expected 13)", message)
self.assertIn("firmware_revision=0 (expected 15)", message)
self.assertIn("missing_frame_ids=0x306", message)
self.assertIn("max_hall_counts=480,374,917,647", message)
self.assertTrue(bus.closed)