feat: improve mode and peripheral orchestration

This commit is contained in:
Miayui
2026-09-21 00:13:47 +08:00
parent 89707a42e2
commit 448c8b31a0
39 changed files with 3068 additions and 277 deletions
@@ -48,6 +48,23 @@ def _learned_light() -> dict[str, object]:
}
def _learned_light_power_on() -> dict[str, object]:
return {
"id": "ir-slot:romance-light:1",
"status": "learned",
"enabled": True,
"device_id": "romance-light",
"device_name": "氛围灯带",
"object_names": ["氛围灯带", "灯带"],
"device_type": "light",
"card_uid": "2CC8B103",
"action": "打开",
"action_names": ["打开", "开启", "点亮"],
"risk": "low",
"slot": 1,
}
def test_scene_composer_mixed_can_ir_preview_save_and_revalidate(
tmp_path: Path,
) -> None:
@@ -61,13 +78,19 @@ def test_scene_composer_mixed_can_ir_preview_save_and_revalidate(
SimulationGateway(),
catalog_db_path=tmp_path / "infrared.sqlite3",
)
extension.sync_peripheral_catalog([_learned_light()])
extension.sync_peripheral_catalog(
[_learned_light_power_on(), _learned_light()]
)
catalog = AssistantCapabilityCatalog(
service,
peripheral_provider=extension.list_peripheral_routing_capabilities,
)
context = catalog.scene_composition_context(catalog.snapshot())
capability_ref = context["peripheral_actions"][0]["ref"]
capability_ref = next(
item["ref"]
for item in context["peripheral_actions"]
if "红色" in str(item.get("action_label") or "")
)
encoded_context = json.dumps(context, ensure_ascii=False)
assert "2CC8B103" not in encoded_context
assert '"slot":7' not in encoded_context
@@ -126,13 +149,19 @@ def test_scene_composer_mixed_can_ir_preview_save_and_revalidate(
"climate",
"self_extension",
]
assert preview["mode_profile_draft"]["operation_count"] == 2
assert preview["mode_profile_draft"]["operation_count"] == 3
assert set(preview["function_configs"]) == {"native_climate", "self_extension"}
infrared_command = preview["command_plans"]["self_extension"]["spec"][
infrared_commands = preview["command_plans"]["self_extension"]["spec"][
"commands"
][0]
assert infrared_command["message"] == "infrared.emit"
assert infrared_command["signals"] == {"slot": 7}
]
assert [command["message"] for command in infrared_commands] == [
"infrared.emit",
"infrared.emit",
]
assert [command["signals"] for command in infrared_commands] == [
{"slot": 1},
{"slot": 7},
]
assert preview["infrared_actions"][0]["parse_source"] == (
"scene_composer_capability_ref"
)
@@ -156,9 +185,10 @@ def test_scene_composer_mixed_can_ir_preview_save_and_revalidate(
assert [operation.capability for operation in profile.operations] == [
"climate.set_temperature",
"infrared.emit",
"infrared.emit",
]
entries = handler._saved_mode_infrared_entries(profile)
assert [entry["capability"]["slot"] for entry in entries] == [7]
assert [entry["capability"]["slot"] for entry in entries] == [1, 7]
native_execution = service.execute_mode_profile_card(
profile.id,
conversation_id="conv-saved-scene-peripheral",
@@ -179,7 +209,7 @@ def test_scene_composer_mixed_can_ir_preview_save_and_revalidate(
entries,
)
assert executed["status"] == "succeeded"
assert [action["slot"] for action in executed["infrared_actions"]] == [7]
assert [action["slot"] for action in executed["infrared_actions"]] == [1, 7]
invoked = handler._execute_request_with_peripherals(
"/api/requests/preview",
{
@@ -196,7 +226,7 @@ def test_scene_composer_mixed_can_ir_preview_save_and_revalidate(
assert invoked is not None
assert invoked["status"] == "succeeded"
assert invoked["execution_mode"] == "dry_run"
assert [action["slot"] for action in invoked["infrared_actions"]] == [7]
assert [action["slot"] for action in invoked["infrared_actions"]] == [1, 7]
template_plan = _catalog_exact_scene_template_plan(
catalog.snapshot(),
@@ -301,8 +331,8 @@ def test_scene_composer_mixed_can_ir_preview_save_and_revalidate(
assert explicit is not None
assert explicit["status"] == "succeeded"
assert explicit["execution_mode"] == "dry_run"
assert explicit["mode_profile_draft"]["operation_count"] == 2
assert explicit["infrared_actions"][0]["slot"] == 7
assert explicit["mode_profile_draft"]["operation_count"] == 3
assert [action["slot"] for action in explicit["infrared_actions"]] == [1, 7]
# Removing the durable NFC whitelist invalidates both cached refs and saved
# mode execution before any transport can be reached.