feat: 完善 N7 智能座舱交互与控制链路
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
@@ -11,6 +12,16 @@ from cognitive_agent.infrastructure.llm.openai_responses import OpenAIIntentErro
|
||||
|
||||
class SeatServiceIntegrationTests(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.memory_environment = patch.dict(
|
||||
os.environ,
|
||||
{
|
||||
"COGNITIVE_AGENT_DRIVER_SEAT_MEMORY_PATH": str(
|
||||
REPOSITORY_ROOT / "tests" / "fixtures" / "driver_seat_memory.json"
|
||||
)
|
||||
},
|
||||
)
|
||||
self.memory_environment.start()
|
||||
self.addCleanup(self.memory_environment.stop)
|
||||
self.service = SeatDemoService(REPOSITORY_ROOT)
|
||||
self.temporary_directory = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temporary_directory.cleanup)
|
||||
@@ -32,6 +43,26 @@ class SeatServiceIntegrationTests(unittest.TestCase):
|
||||
for event in result["trace_events"]:
|
||||
self.assertEqual(self.service.contracts.validate(event), [])
|
||||
|
||||
def test_explicit_legrest_height_does_not_execute_the_seat_height_axis(self) -> None:
|
||||
result = self.service.preview_native_can(
|
||||
"副驾腿托高度调到50%",
|
||||
provider="local",
|
||||
execution_mode="dry_run",
|
||||
conversation_id="conv-legrest-height-regression",
|
||||
)
|
||||
|
||||
self.assertEqual(result["status"], "succeeded")
|
||||
actions = result["intent_ir"]["spec"]["actions"]
|
||||
self.assertEqual(len(actions), 1)
|
||||
self.assertEqual(actions[0]["capability"], "seat.set_legrest_height")
|
||||
self.assertEqual(actions[0]["parameters"], {"position_pct": 50})
|
||||
self.assertEqual(
|
||||
result["actuator_state"]["passenger"]["position"]["legrest_height"][
|
||||
"position_pct"
|
||||
],
|
||||
50,
|
||||
)
|
||||
|
||||
def test_dynamic_mode_runs_until_explicit_natural_language_stop(self) -> None:
|
||||
conversation_id = "conv-dynamic-stop"
|
||||
started = self.service.process(
|
||||
|
||||
@@ -284,6 +284,26 @@ class LocalIntentParserTests(unittest.TestCase):
|
||||
self.assertEqual(action["position_pct"], position)
|
||||
self.assertNotIn("motion_intent", action)
|
||||
|
||||
def test_explicit_legrest_height_beats_generic_seat_height_alias(self) -> None:
|
||||
for utterance in (
|
||||
"副驾腿托高度调到50%",
|
||||
"副驾小腿托高度设置为50%",
|
||||
"脚托高度调至50%",
|
||||
"腿部支撑高度设置到50%",
|
||||
):
|
||||
with self.subTest(utterance=utterance):
|
||||
result = parse_local_intent(utterance, self.motion_context())
|
||||
|
||||
self.assertEqual(result["ambiguities"], [])
|
||||
self.assertEqual(len(result["actions"]), 1)
|
||||
self.assertEqual(result["actions"][0]["axis"], "legrest_height")
|
||||
self.assertEqual(result["actions"][0]["position_pct"], 50)
|
||||
|
||||
seat_height = parse_local_intent("副驾高度调到25%", self.motion_context())
|
||||
self.assertEqual(len(seat_height["actions"]), 1)
|
||||
self.assertEqual(seat_height["actions"][0]["axis"], "cushion_tilt")
|
||||
self.assertEqual(seat_height["actions"][0]["position_pct"], 25)
|
||||
|
||||
def test_rejects_relative_motion_without_state_and_clamps_endpoint_overflow(self) -> None:
|
||||
missing = parse_local_intent("靠背向前移动10度")
|
||||
context = self.motion_context()
|
||||
@@ -414,6 +434,16 @@ class LocalIntentParserTests(unittest.TestCase):
|
||||
"坐盆抬到最上方": ("cushion_tilt", 0),
|
||||
"坐盆降到最下方": ("cushion_tilt", 100),
|
||||
"靠背放倒到最后": ("backrest_recline", 100),
|
||||
"副驾座椅靠背向后移动到最大位置": ("backrest_recline", 100),
|
||||
"靠背往后调整至极限位置": ("backrest_recline", 100),
|
||||
"靠背调整到最大位置": ("backrest_recline", 100),
|
||||
"副驾靠背往后移到底": ("backrest_recline", 100),
|
||||
"副驾椅背后移到底": ("backrest_recline", 100),
|
||||
"副驾靠背调到最后位置": ("backrest_recline", 100),
|
||||
"靠背向前移动到最大位置": ("backrest_recline", 0),
|
||||
"副驾靠背向前移到底": ("backrest_recline", 0),
|
||||
"副驾椅背前倾到底": ("backrest_recline", 0),
|
||||
"靠背设置为最小角度": ("backrest_recline", 0),
|
||||
"腿托升到最高": ("legrest_height", 100),
|
||||
"腿托降到最低": ("legrest_height", 0),
|
||||
}
|
||||
@@ -426,6 +456,57 @@ class LocalIntentParserTests(unittest.TestCase):
|
||||
[expected],
|
||||
)
|
||||
|
||||
def test_compositional_directional_endpoints_cover_every_seat_axis(self) -> None:
|
||||
cases = {
|
||||
"滑轨向前调整到最大位置": ("longitudinal", 0),
|
||||
"前后往后移动至极限位置": ("longitudinal", 100),
|
||||
"纵向朝前调节到极限位置": ("longitudinal", 0),
|
||||
"水平向后设置到最大行程": ("longitudinal", 100),
|
||||
"座椅高度向上调整到最大位置": ("cushion_tilt", 0),
|
||||
"坐垫往下移动至极限位置": ("cushion_tilt", 100),
|
||||
"坐盆倾角上调到最大位置": ("cushion_tilt", 0),
|
||||
"坐垫倾角向下设置到最大行程": ("cushion_tilt", 100),
|
||||
"靠背向前调整到最大位置": ("backrest_recline", 0),
|
||||
"椅背往后移动至极限位置": ("backrest_recline", 100),
|
||||
"靠背前倾调到最大角度": ("backrest_recline", 0),
|
||||
"椅背后倾设置到最大行程": ("backrest_recline", 100),
|
||||
"腿托向上调整到最大位置": ("legrest_height", 100),
|
||||
"脚托往下移动至极限位置": ("legrest_height", 0),
|
||||
"小腿托上调到最大位置": ("legrest_height", 100),
|
||||
"腿部支撑高度向下设置到最大行程": ("legrest_height", 0),
|
||||
}
|
||||
for utterance, expected in cases.items():
|
||||
with self.subTest(utterance=utterance):
|
||||
result = parse_local_intent(utterance)
|
||||
self.assertEqual(result["ambiguities"], [])
|
||||
self.assertEqual(
|
||||
[(item["axis"], item["position_pct"]) for item in result["actions"]],
|
||||
[expected],
|
||||
)
|
||||
|
||||
def test_endpoint_conflicts_and_directionless_extremes_fail_with_a_real_hint(
|
||||
self,
|
||||
) -> None:
|
||||
for utterance in (
|
||||
"滑轨向前移到最后方",
|
||||
"座椅高度向上调到最低",
|
||||
"靠背向后调到最前",
|
||||
"腿托向上调到最低",
|
||||
"靠背向上调整到最大位置",
|
||||
"腿托调整到极限位置",
|
||||
"滑轨调整到最大位置",
|
||||
):
|
||||
with self.subTest(utterance=utterance):
|
||||
result = parse_local_intent(utterance)
|
||||
self.assertEqual(result["actions"], [])
|
||||
questions = [
|
||||
item["question"]
|
||||
for item in result["ambiguities"]
|
||||
if item["field"].startswith("passenger.position.")
|
||||
]
|
||||
self.assertEqual(len(questions), 1)
|
||||
self.assertIn("请", questions[0])
|
||||
|
||||
def test_parses_normal_half_second_and_minimum_clamped_timed_motion(self) -> None:
|
||||
normal = parse_local_intent("滑轨向后移动2秒", self.motion_context())
|
||||
half_second = parse_local_intent("靠背向后移动半秒", self.motion_context())
|
||||
|
||||
Reference in New Issue
Block a user