fix: restore mode clicks and compose seat-aware assistant scenes

This commit is contained in:
vee
2026-09-12 13:33:38 +08:00
parent 76057be044
commit d09b5967f8
28 changed files with 1247 additions and 44 deletions
+113 -1
View File
@@ -12,6 +12,7 @@ import pytest
from cognitive_agent.application.assistant_capabilities import AssistantCapabilityCatalog
from cognitive_agent.application.codex_assistant import CodexAssistantService
from cognitive_agent.application.mode_profile import ModeProfileRegistry
from cognitive_agent.application.scene_composer import normalize_scene_output
from cognitive_agent.application.seat_service import REPOSITORY_ROOT, SeatDemoService
@@ -94,6 +95,7 @@ def _assistant_preview(
client.available = False
assistant = CodexAssistantService(client)
snapshot = catalog.snapshot(vehicle_id="denza_n7")
fast_answer = catalog.fast_answer(message, snapshot)
events: list[dict[str, object]] = []
raw_results: list[dict[str, object]] = []
passed_plans: list[dict[str, object] | None] = []
@@ -122,6 +124,7 @@ def _assistant_preview(
conversation_id=conversation_id,
principal="scene-template-hybrid-test",
history=[],
authoritative_answer=fast_answer.answer if fast_answer else None,
emit=lambda event: events.append(event) or True,
execute_control=execute_control,
capability_snapshot=snapshot,
@@ -141,7 +144,7 @@ def test_all_production_scene_templates_complete_the_full_local_dry_run(
templates = snapshot["scene_templates"]
assert isinstance(templates, list)
assert len(templates) == 12
assert len(templates) == 13
assert all(template["assistant_callable"] is True for template in templates)
with patch.object(
@@ -339,6 +342,115 @@ def test_explicit_settings_on_a_purpose_scene_bypass_template_defaults(
client.start_turn.assert_not_called()
@pytest.mark.parametrize(
("message", "expected_name", "template_id"),
(
("构建一个座椅舒适的功能模式", "座椅舒适模式", "seat-comfort"),
("构建一个让人坐着放松的功能模式", "坐着放松模式", "relaxation"),
("请帮我创建一个适合乘坐舒适的模式吧", "乘坐舒适模式", "seat-comfort"),
("帮我构建一个让我们坐着舒服的功能模式", "坐着舒服模式", "seat-comfort"),
("创建一个座椅放松模式并预览", "座椅放松模式", "relaxation"),
("构建一个长途舒适模式", "长途舒适模式", "long-trip-comfort"),
),
)
def test_seating_comfort_requests_preview_both_seats_with_no_model_or_hardware_call(
hybrid_service: tuple[SeatDemoService, AssistantCapabilityCatalog, Path],
message: str,
expected_name: str,
template_id: str,
) -> None:
service, catalog, user_root = hybrid_service
with patch.object(
service.hardware_execution,
"reserve",
side_effect=AssertionError("seat comfort preview reached hardware execution"),
):
response, result, _events, client, _plans = _assistant_preview(
service, catalog, message, conversation_id="conv-seat-comfort-preview",
)
assert response["route"] == "scene_template"
assert response["success"] is True
assert result["status"] == "succeeded"
assert result["execution_mode"] == "dry_run"
assert result["hardware_execution_allowed"] is False
assert result["mode_profile_draft"]["name"] == expected_name
assert result["mode_profile_draft"]["source_template_id"] == template_id
seat_actions = {
(capability, target): parameters
for (capability, target), parameters in _action_map(result).items()
if capability.startswith("seat.")
}
assert {target for _capability, target in seat_actions} == {"driver", "passenger"}
assert all(
"driver_axis" not in capability and "driver_position" not in capability
for capability, _target in seat_actions
)
assert ("seat.set_driver_massage_native", "passenger") not in seat_actions
if template_id in {"seat-comfort", "long-trip-comfort"}:
assert seat_actions["seat.set_driver_ventilation_native", "driver"] == {
"state": "on", "level": 2,
}
assert seat_actions["seat.set_ventilation", "passenger"] == {
"state": "on", "level": 1,
}
client.start_structured_turn.assert_not_called()
client.start_turn.assert_not_called()
assert not list(user_root.rglob("*.yaml"))
@pytest.mark.parametrize("name", ("云端座椅舒展模式", "晚间乘坐释压模式"))
def test_unregistered_seat_scene_keeps_both_explicit_targets_through_native_merge(
hybrid_service: tuple[SeatDemoService, AssistantCapabilityCatalog, Path],
name: str,
) -> None:
service, catalog, user_root = hybrid_service
plan = normalize_scene_output({
"requests": [
{"capability": "seat.set_driver_massage_native", "target_scope": "driver",
"parameters": {"action": "mode", "mode": "relax"}},
{"capability": "seat.set_driver_heating_native", "target_scope": "driver",
"parameters": {"state": "on", "level": 2}},
{"capability": "seat.set_backrest_recline", "target_scope": "passenger",
"parameters": {"position_pct": 45}},
{"capability": "seat.set_heating", "target_scope": "passenger",
"parameters": {"state": "on", "level": 1}},
],
"ambiguities": [], "confidence": 0.95,
}, catalog.scene_composition_context())
with patch.object(
service.hardware_execution, "reserve",
side_effect=AssertionError("scene composition reached hardware execution"),
):
result = service.preview_native_can(
f"构建一个{name}", provider="local", conversation_id="conv-seat-generated",
execution_mode="hardware", vehicle_id="denza_n7", assistant_plan=plan,
)
assert result["status"] == "succeeded"
assert result["execution_mode"] == "dry_run"
assert result["mode_profile_draft"]["generation_source"] == "codex_scene_composition"
assert set(_action_map(result)) == {
("seat.set_driver_massage_native", "driver"),
("seat.set_driver_heating_native", "driver"),
("seat.set_backrest_recline", "passenger"),
("seat.set_heating", "passenger"),
}
assert not list(user_root.rglob("*.yaml"))
def test_explicit_unscoped_seat_instruction_keeps_target_ambiguity_guard(
hybrid_service: tuple[SeatDemoService, AssistantCapabilityCatalog, Path],
) -> None:
service, _catalog, _user_root = hybrid_service
result = service.preview_native_can(
"构建一个舒展模式,座椅靠背调整到45%", provider="local",
conversation_id="conv-seat-explicit-target", execution_mode="hardware",
vehicle_id="denza_n7",
)
assert result["status"] != "succeeded"
assert result.get("mode_profile_draft") is None
assert result["hardware_execution_allowed"] is False
def test_template_metadata_cannot_authorize_modified_or_stale_template_actions(
hybrid_service: tuple[SeatDemoService, AssistantCapabilityCatalog, Path],
) -> None: