from __future__ import annotations import tempfile import unittest from pathlib import Path from unittest.mock import MagicMock, patch from cognitive_agent.application.domain_runtime import ConfiguredDomainRuntime from cognitive_agent.application.mode_profile import ModeProfileRegistry from cognitive_agent.application.seat_service import REPOSITORY_ROOT, SeatDemoService from cognitive_agent.infrastructure.can.hardware import HardwareSafetyError class ConfiguredDomainRuntimeTests(unittest.TestCase): def test_matrix_backed_domain_frames(self) -> None: cases = { "climate": ( [ { "domain": "climate", "capability": "climate.set_temperature", "target": "driver", "parameters": {"temperature_c": 22}, "operation": "set", "reason": "test", }, { "domain": "climate", "capability": "climate.set_fan_level", "target": "vehicle", "parameters": {"level": 3}, "operation": "set", "reason": "test", }, ], ["05 16 00 00 00 00 00 00", "04 04 00 00 00 00 00 00"], ), "roof": ( [ { "domain": "roof", "capability": "roof.set_transmittance", "target": "vehicle", "parameters": {"transmittance_pct": 30}, "operation": "set", "reason": "test", }, { "domain": "roof", "capability": "roof.set_shade_position", "target": "vehicle", "parameters": {"position_pct": 60}, "operation": "set", "reason": "test", }, ], ["13 00 1E 00", "04 00 00 00 3C"], ), "ambient_light": ( [ { "domain": "ambient_light", "capability": "ambient_light.set_illumination", "target": "vehicle", "parameters": { "color_hex": "#FF8040", "brightness_pct": 60, }, "operation": "set", "reason": "test", } ], ["2B FF 80 40 3C"], ), } for domain, (actions, expected_frames) in cases.items(): with self.subTest(domain=domain): runtime = ConfiguredDomainRuntime(REPOSITORY_ROOT, domain) config = runtime.build_function_config( actions, "req-test-domain-frame", "test" ) plan = runtime.compile(config) report = runtime.execute(plan, config) frames = [ item["telemetry"]["command_frame"]["data_hex"] for item in report["spec"]["results"] ] self.assertEqual(frames, expected_frames) class MultiDomainServiceTests(unittest.TestCase): def setUp(self) -> None: self.service = SeatDemoService(REPOSITORY_ROOT) self.service.openai.api_key = "test-key" self.temporary_directory = tempfile.TemporaryDirectory() self.addCleanup(self.temporary_directory.cleanup) self.service.artifact_root = Path(self.temporary_directory.name) def test_four_domain_scene_is_generated_executed_and_persisted(self) -> None: model_output = { "detected_domains": ["seat", "climate", "roof", "ambient_light"], "requests": [ { "domain": "seat", "capability": "seat.set_backrest_recline", "target_scope": "passenger", "operation": "set", "parameters": [{"name": "position_pct", "value": 55}], "reason": "comfortable viewing posture", }, { "domain": "climate", "capability": "climate.set_temperature", "target_scope": "vehicle", "operation": "set", "parameters": [{"name": "temperature_c", "value": 24}], "reason": "comfortable cabin", }, { "domain": "roof", "capability": "roof.set_transmittance", "target_scope": "vehicle", "operation": "set", "parameters": [{"name": "transmittance_pct", "value": 20}], "reason": "reduce glare", }, { "domain": "ambient_light", "capability": "ambient_light.set_illumination", "target_scope": "vehicle", "operation": "set", "parameters": [ {"name": "color_hex", "value": "#FF8040"}, {"name": "brightness_pct", "value": 35}, ], "reason": "warm cinema lighting", }, ], "ambiguities": [], "decision_summary": ["生成四域观影目标。"], "confidence": 0.95, } with patch.object(self.service.openai, "interpret", return_value=model_output): result = self.service.process( "进入观影状态", "openai", "conv-four-domain-test", ) self.assertEqual(result["status"], "succeeded") self.assertEqual( set(result["function_configs"]), {"seat", "climate", "roof", "ambient_light"}, ) self.assertEqual(len(result["scene_config"]["spec"]["function_refs"]), 4) self.assertEqual( {item["domain"] for item in result["execution_report"]["spec"]["results"]}, {"seat", "climate", "roof", "ambient_light"}, ) self.assertEqual(result["domain_state"]["roof"]["transmittance_pct"], 20) self.assertEqual( result["domain_state"]["ambient_light"]["color_hex"], "#FF8040" ) run_path = self.service.artifact_root / result["request_id"] self.assertTrue((run_path / "scene.yaml").is_file()) for domain in ("seat", "climate", "roof", "ambient_light"): self.assertTrue((run_path / "functions" / f"{domain}.yaml").is_file()) self.assertTrue( (run_path / "command-plans" / f"{domain}.yaml").is_file() ) def test_domain_state_is_supplied_to_follow_up_model_turn(self) -> None: first_plan = { "detected_domains": ["roof"], "requests": [ { "domain": "roof", "capability": "roof.set_transmittance", "target_scope": "vehicle", "operation": "set", "parameters": [{"name": "transmittance_pct", "value": 30}], "reason": "initial target", } ], "ambiguities": [], "decision_summary": ["天幕透光率设为30%。"], "confidence": 0.96, } second_plan = { **first_plan, "requests": [ { **first_plan["requests"][0], "operation": "decrease", "parameters": [{"name": "transmittance_pct", "value": 20}], "reason": "resolved relative to current 30 percent", } ], "decision_summary": ["基于当前30%继续调暗到20%。"], } with patch.object( self.service.openai, "interpret", side_effect=[first_plan, second_plan], ) as interpret: self.service.process( "天幕透光率调到30%", "openai", "conv-roof-follow-up", ) result = self.service.process( "再暗一点", "openai", "conv-roof-follow-up", ) second_context = interpret.call_args_list[1].args[1] self.assertEqual( second_context["domain_devices"]["roof"]["transmittance_pct"], 30 ) self.assertEqual(result["domain_state"]["roof"]["transmittance_pct"], 20) self.assertEqual(result["conversation_turn"], 2) def test_named_mode_profile_executes_without_model_expansion(self) -> None: model_output = { "detected_domains": ["seat"], "requests": [], "ambiguities": [], "decision_summary": ["用户要求调用已有零重力模式。"], "confidence": 0.94, } with patch.object(self.service.openai, "interpret", return_value=model_output): result = self.service.process( "副驾驶进入零重力模式", "openai", "conv-zero-gravity-mode", vehicle_id="denza_n7", ) self.assertEqual(result["status"], "succeeded") self.assertEqual(result["matched_modes"][0]["id"], "zero_gravity") operations = result["function_config"]["spec"]["operations"] by_capability = {item["capability"]: item for item in operations} self.assertEqual( by_capability["seat.set_longitudinal_position"]["parameters"], {"position_pct": 100}, ) self.assertEqual( by_capability["seat.set_cushion_tilt"]["parameters"], {"position_pct": 100}, ) self.assertEqual( by_capability["seat.set_backrest_recline"]["parameters"], {"position_pct": 81, "angle_deg": 150}, ) self.assertEqual( by_capability["seat.set_legrest_height"]["parameters"], {"position_pct": 94, "angle_deg": 163}, ) def test_named_mode_profile_suppresses_generic_local_parser_ambiguity(self) -> None: result = self.service.process( "副驾进入零重力模式", "local", "conv-zero-gravity-local-mode", vehicle_id="denza_n7", ) self.assertEqual(result["status"], "succeeded") self.assertEqual(result["matched_modes"][0]["id"], "zero_gravity") self.assertFalse( any( issue.get("code") == "AMBIGUOUS_INTENT" for issue in result["validation"] ) ) def test_named_mode_profile_combines_with_temporary_roof_request(self) -> None: model_output = { "detected_domains": ["roof"], "requests": [ { "domain": "roof", "capability": "roof.set_transmittance", "target_scope": "vehicle", "operation": "set", "parameters": [{"name": "transmittance_pct", "value": 20}], "reason": "用户同时要求天幕调暗。", } ], "ambiguities": [], "decision_summary": ["零重力之外还需设置天幕。"], "confidence": 0.96, } with patch.object(self.service.openai, "interpret", return_value=model_output): result = self.service.process( "副驾零重力模式,天幕透光率调到20%", "openai", "conv-mode-plus-roof", vehicle_id="denza_n7", ) self.assertEqual(result["status"], "succeeded") self.assertEqual(set(result["function_configs"]), {"seat", "roof"}) self.assertEqual(result["scene_config"]["kind"], "SceneConfig") self.assertEqual(result["domain_state"]["roof"]["transmittance_pct"], 20) self.assertIn( "seat.set_backrest_recline", { item["capability"] for item in result["function_configs"]["seat"]["spec"]["operations"] }, ) def test_hardware_orchestration_rejects_ch0_seat_and_virtual_roof_before_send( self, ) -> None: model_output = { "detected_domains": ["seat", "roof"], "requests": [ { "domain": "seat", "capability": "seat.set_backrest_recline", "target_scope": "passenger", "operation": "set", "parameters": [{"name": "position_pct", "value": 55}], "reason": "调整副驾靠背。", }, { "domain": "roof", "capability": "roof.set_transmittance", "target_scope": "vehicle", "operation": "set", "parameters": [{"name": "transmittance_pct", "value": 20}], "reason": "降低天幕透光率。", }, ], "ambiguities": [], "decision_summary": ["执行副驾与天幕联合模式。"], "confidence": 0.96, } hardware_executor = MagicMock() with ( patch.object(self.service.openai, "interpret", return_value=model_output), patch.object( self.service, "_new_hardware_executor", return_value=hardware_executor, ) as executor_factory, ): with self.assertRaisesRegex( HardwareSafetyError, "hardware mode refuses virtual or unverified vehicle actions", ): self.service.process( "副驾靠背调到55%,天幕透光率调到20%", "openai", "conv-mixed-hardware-success", execution_mode="hardware", approval_token="test-token", vehicle_id="denza_n7", ) executor_factory.assert_not_called() hardware_executor.execute.assert_not_called() def test_hardware_orchestration_rejects_ch0_motion_before_executor_creation( self, ) -> None: model_output = { "detected_domains": ["seat", "roof"], "requests": [ { "domain": "seat", "capability": "seat.set_longitudinal_position", "target_scope": "passenger", "operation": "set", "parameters": [{"name": "position_pct", "value": 100}], "reason": "移动副驾。", }, { "domain": "roof", "capability": "roof.set_transmittance", "target_scope": "vehicle", "operation": "set", "parameters": [{"name": "transmittance_pct", "value": 20}], "reason": "降低天幕透光率。", }, ], "ambiguities": [], "decision_summary": ["执行副驾与天幕联合模式。"], "confidence": 0.96, } hardware_executor = MagicMock() with ( patch.object(self.service.openai, "interpret", return_value=model_output), patch.object( self.service, "_new_hardware_executor", return_value=hardware_executor, ) as executor_factory, ): with self.assertRaisesRegex( HardwareSafetyError, "hardware mode refuses virtual or unverified vehicle actions", ): self.service.process( "副驾水平移到100%,天幕透光率调到20%", "openai", "conv-mixed-hardware-failure", execution_mode="hardware", approval_token="test-token", vehicle_id="denza_n7", ) executor_factory.assert_not_called() hardware_executor.execute.assert_not_called() def test_reference_mode_library_modes_execute_for_denza(self) -> None: model_output = { "detected_domains": ["seat"], "requests": [], "ambiguities": [], "decision_summary": ["用户要求调用已有长期模式。"], "confidence": 0.95, } utterances = [ "副驾驶进入零重力模式", "副驾驶进入巡航沙发模式", "副驾驶进入休闲躺椅模式", "副驾驶进入小憩模式", "副驾驶进入轻松进出模式", "副驾驶进入宝宝午睡模式", "副驾驶进入办公模式", "副驾驶进入冥想空间模式", "副驾驶进入电感沙滩椅", "副驾驶进入女王副驾模式", "副驾驶进入小腿解压悬浮模式", ] with patch.object(self.service.openai, "interpret", return_value=model_output): for index, utterance in enumerate(utterances): with self.subTest(utterance=utterance): result = self.service.process( utterance, "openai", f"conv-reference-mode-{index}", vehicle_id="denza_n7", ) self.assertEqual(result["status"], "succeeded") self.assertTrue(result["matched_modes"]) self.assertTrue( result["function_config"] or result["function_configs"] ) def test_save_recent_successful_actions_as_long_term_mode_profile(self) -> None: self.service.mode_profiles = ModeProfileRegistry( self.service.artifact_root / "modes" ) model_output = { "detected_domains": ["roof"], "requests": [ { "domain": "roof", "capability": "roof.set_transmittance", "target_scope": "vehicle", "operation": "set", "parameters": [{"name": "transmittance_pct", "value": 35}], "reason": "保存前先形成一个可复用动作。", } ], "ambiguities": [], "decision_summary": ["天幕透光率设为35%。"], "confidence": 0.96, } with patch.object(self.service.openai, "interpret", return_value=model_output): first = self.service.process( "天幕透光率调到35%", "openai", "conv-save-mode-profile", vehicle_id="denza_n7", ) saved = self.service.process( "这个模式不错,固化为露营模式", "local", "conv-save-mode-profile", vehicle_id="denza_n7", ) self.assertEqual(first["status"], "succeeded") self.assertEqual(saved["status"], "succeeded") self.assertIsNone(saved["command_plan"]) self.assertEqual(saved["mode_profile"]["name"], "露营模式") telemetry = saved["execution_report"]["spec"]["results"][0]["telemetry"] self.assertEqual(telemetry["operation"], "save_mode_profile") self.assertFalse(telemetry["can_command_emitted"]) registry = ModeProfileRegistry(self.service.artifact_root / "modes") matched = registry.match_text("进入露营模式", vehicle_id="denza_n7") requests = registry.requests_for_profiles(matched) self.assertEqual(requests[0]["capability"], "roof.set_transmittance") self.assertEqual( requests[0]["parameters"], [{"name": "transmittance_pct", "value": 35}], ) self.assertEqual( registry.match_text("进入露营模式", vehicle_id="other_vehicle"), [], ) def test_mode_card_editor_persists_only_server_generated_command_flow(self) -> None: mode_root = Path(self.temporary_directory.name) / "mode-card-presets" user_root = Path(self.temporary_directory.name) / "mode-card-user" preset = mode_root / "vehicles" / "denza_n7" / "office.yaml" preset.parent.mkdir(parents=True) preset.write_text( """ id: office name: 办公模式 icon: briefcase scope: vehicle_ids: [denza_n7] operations: - domain: climate capability: climate.set_temperature target_scope: passenger parameters: temperature_c: 24 """.strip() + "\n", encoding="utf-8", ) self.service.mode_profiles = ModeProfileRegistry( mode_root, user_root=user_root ) model_output = { "detected_domains": ["climate"], "requests": [ { "domain": "climate", "capability": "climate.set_temperature", "target_scope": "passenger", "operation": "set", "parameters": [{"name": "temperature_c", "value": 24}], "reason": "办公温度。", } ], "ambiguities": [], "decision_summary": ["副驾温度设置为24度。"], "confidence": 0.97, } instruction = "副驾空调温度设置为24度" with patch.object(self.service.openai, "interpret", return_value=model_output): generated = self.service.process( instruction, "openai", "conv-mode-card-editor", vehicle_id="denza_n7", ) saved = self.service.save_mode_profile_card( "office", "专注办公模式", instruction, generated["request_id"], "denza_n7", ) self.assertEqual(saved["status"], "succeeded") self.assertEqual(saved["storage"], "persistent_yaml") self.assertEqual(saved["mode_profile"]["origin"], "customized") self.assertEqual(saved["mode_profile"]["instruction"], instruction) self.assertTrue(saved["mode_profile"]["command_flow"]["plans"]) self.assertTrue( saved["mode_profile"]["command_flow"]["function_configs"] ) reloaded = ModeProfileRegistry(mode_root, user_root=user_root) persisted = next( item for item in reloaded.public_modes("denza_n7") if item["id"] == "office" ) self.assertEqual(persisted["name"], "专注办公模式") with self.assertRaisesRegex(ValueError, "重新点击执行"): self.service.save_mode_profile_card( "office", "专注办公模式", "副驾空调温度设置为25度", generated["request_id"], "denza_n7", ) def test_build_named_mode_executes_and_persists_in_one_turn(self) -> None: mode_root = Path(self.temporary_directory.name) / "modes" self.service.mode_profiles = ModeProfileRegistry(mode_root) model_output = { "detected_domains": ["ambient_light", "climate"], "requests": [ { "domain": "ambient_light", "capability": "ambient_light.set_illumination", "target_scope": "vehicle", "operation": "set", "parameters": [ {"name": "color_hex", "value": "#B040FF"}, {"name": "brightness_pct", "value": 60}, ], "reason": "营造K歌氛围。", }, { "domain": "climate", "capability": "climate.set_temperature", "target_scope": "vehicle", "operation": "set", "parameters": [{"name": "temperature_c", "value": 24}], "reason": "保持K歌时的座舱舒适度。", }, ], "ambiguities": [], "decision_summary": ["已构建K歌场景。"], "confidence": 0.94, } with patch.object(self.service.openai, "interpret", return_value=model_output): built = self.service.process( "构建一个K歌模式", "openai", "conv-build-karaoke-mode", vehicle_id="denza_n7", ) self.assertEqual(built["status"], "succeeded") self.assertEqual(built["mode_profile"]["name"], "K歌模式") self.assertEqual(built["mode_creation"]["source_status"], "succeeded") self.assertEqual(built["mode_creation"]["operation_count"], 2) self.assertIn( "K歌模式", { mode["name"] for mode in self.service.runtime_info()["modes"] }, ) matched = self.service.mode_profiles.match_text( "进入K歌模式", vehicle_id="denza_n7" ) self.assertEqual([profile.name for profile in matched], ["K歌模式"]) self.assertTrue(Path(built["mode_profile"]["source"]).is_file()) def test_build_named_mode_is_always_a_dry_run_configuration_workflow(self) -> None: mode_root = Path(self.temporary_directory.name) / "hardware-modes" self.service.mode_profiles = ModeProfileRegistry(mode_root) model_output = { "detected_domains": ["ambient_light"], "requests": [ { "domain": "ambient_light", "capability": "ambient_light.set_illumination", "target_scope": "vehicle", "operation": "set", "parameters": [ {"name": "color_hex", "value": "#B040FF"}, {"name": "brightness_pct", "value": 60}, ], "reason": "构建K歌氛围。", } ], "ambiguities": [], "decision_summary": ["构建K歌灯光。"], "confidence": 0.95, } with patch.object(self.service.openai, "interpret", return_value=model_output): built = self.service.process( "构建一个K歌模式", "openai", "conv-build-karaoke-hardware-mode", execution_mode="hardware", vehicle_id="denza_n7", hardware_access_bypass=False, ) self.assertEqual(built["status"], "succeeded") self.assertEqual(built["execution_mode"], "dry_run") self.assertFalse(built["hardware_execution_allowed"]) self.assertEqual(built["mode_profile"]["name"], "K歌模式") def test_create_mode_language_does_not_match_ordinary_mode_execution(self) -> None: self.assertEqual( self.service._parse_mode_profile_create_name("创建一个K歌模式"), "K歌模式", ) self.assertEqual( self.service._parse_mode_profile_create_name("新增冥想空间模式"), "冥想空间模式", ) self.assertIsNone( self.service._parse_mode_profile_create_name("进入K歌模式") ) def test_update_and_restore_long_term_mode_profile_are_control_plane_only(self) -> None: self.service.mode_profiles = ModeProfileRegistry( self.service.artifact_root / "modes" ) profile = self.service.mode_profiles.save_mode( "露营模式", [ { "domain": "roof", "capability": "roof.set_transmittance", "target_scope": "vehicle", "operation": "set", "parameters": {"transmittance_pct": 20}, "reason": "原始天幕目标。", } ], vehicle_id="denza_n7", ) model_output = { "detected_domains": ["roof"], "requests": [ { "domain": "roof", "capability": "roof.set_transmittance", "target_scope": "vehicle", "operation": "set", "parameters": [{"name": "transmittance_pct", "value": 50}], "reason": "用户修改长期模式天幕目标。", } ], "ambiguities": [], "decision_summary": ["修改露营模式天幕目标。"], "confidence": 0.96, } with patch.object(self.service.openai, "interpret", return_value=model_output): updated = self.service.process( "修改露营模式,天幕透光率改到50%", "openai", "conv-update-mode-profile", execution_mode="hardware", vehicle_id="denza_n7", ) self.assertEqual(updated["status"], "succeeded") self.assertIsNone(updated["command_plan"]) update_telemetry = updated["execution_report"]["spec"]["results"][0][ "telemetry" ] self.assertEqual(update_telemetry["operation"], "update_mode_profile") self.assertFalse(update_telemetry["can_command_emitted"]) self.assertTrue(Path(profile.source).with_suffix(".yaml.initial.bak").is_file()) registry = ModeProfileRegistry(self.service.artifact_root / "modes") requests = registry.requests_for_profiles( registry.match_text("进入露营模式", vehicle_id="denza_n7") ) self.assertEqual( requests[0]["parameters"], [{"name": "transmittance_pct", "value": 50}], ) restored = self.service.process( "恢复露营模式初始配置", "local", "conv-update-mode-profile", execution_mode="hardware", vehicle_id="denza_n7", ) self.assertEqual(restored["status"], "succeeded") self.assertIsNone(restored["command_plan"]) restore_telemetry = restored["execution_report"]["spec"]["results"][0][ "telemetry" ] self.assertEqual(restore_telemetry["operation"], "restore_mode_profile") self.assertFalse(restore_telemetry["can_command_emitted"]) restored_registry = ModeProfileRegistry(self.service.artifact_root / "modes") restored_requests = restored_registry.requests_for_profiles( restored_registry.match_text("进入露营模式", vehicle_id="denza_n7") ) self.assertEqual( restored_requests[0]["parameters"], [{"name": "transmittance_pct", "value": 20}], ) if __name__ == "__main__": unittest.main()