优化了副驾座椅控制

This commit is contained in:
minghanchen
2026-08-25 11:39:41 +08:00
parent 33c92d1352
commit 9ac8fdface
34 changed files with 31714 additions and 289 deletions
+151 -58
View File
@@ -57,6 +57,9 @@ from cognitive_agent.application.mqtt_ota_seat_executor import ( # noqa: E402
MqttOtaSeatExecutor,
)
from cognitive_agent.application.native_can_intent import merge_native_can_intent # noqa: E402
from cognitive_agent.application.direct_can_control import ( # noqa: E402
build_direct_can_intent,
)
from cognitive_agent.application.native_can_relative import ( # noqa: E402
NativeCanRelativeResolver,
)
@@ -1401,6 +1404,47 @@ class SeatDemoService:
}
return merged
def process_can_commands(
self,
commands: object,
conversation_id: str | None = None,
execution_mode: str = "dry_run",
approval_token: str | None = None,
vehicle_id: str | None = None,
simulation_fault: str = "normal",
*,
hardware_client_id: str | None = None,
hardware_access_bypass: bool = True,
control_transport: str = WIRED_CAN_TRANSPORT,
) -> dict[str, Any]:
"""Compile and execute an exact UI command batch without intent parsing."""
resolved_conversation_id = conversation_id or f"conv-{uuid.uuid4().hex}"
if not CONVERSATION_ID_PATTERN.fullmatch(resolved_conversation_id):
raise ValueError(
"conversation_id must start with conv- and contain only lowercase letters, numbers, or hyphens"
)
vehicle_profile = self.vehicle_profiles.get(vehicle_id)
context = self._context_for_vehicle(
self.conversations.snapshot(resolved_conversation_id),
vehicle_profile,
)
direct_can_batch = build_direct_can_intent(commands, context)
normalized_commands, _parsed = direct_can_batch
return self.process(
";".join(normalized_commands),
provider="local",
conversation_id=resolved_conversation_id,
execution_mode=execution_mode,
approval_token=approval_token,
vehicle_id=vehicle_id,
simulation_fault=simulation_fault,
hardware_client_id=hardware_client_id,
hardware_access_bypass=hardware_access_bypass,
control_transport=control_transport,
_direct_can_batch=direct_can_batch,
)
def process(
self,
utterance: str,
@@ -1420,6 +1464,7 @@ class SeatDemoService:
_model_parse_source: str = "cloud_model",
_allow_empty_control_result: bool = False,
_on_commands_validated: Callable[[dict[str, Any]], None] | None = None,
_direct_can_batch: tuple[list[str], dict[str, Any]] | None = None,
) -> dict[str, Any]:
control_transport = self._validate_control_transport(control_transport)
# Creating a reusable scene is a configuration workflow. Synthesize
@@ -1444,6 +1489,28 @@ class SeatDemoService:
_model_parse_source,
_allow_empty_control_result,
_on_commands_validated,
_direct_can_batch,
)
if control_transport == WIRELESS_MQTT_TRANSPORT:
# The head unit owns both physical CAN channels in wireless mode.
# Local T2G/ZLG hardware access, firmware profiles and the local
# physical-bench lease are unrelated to MQTT relay execution.
return self._process_once(
utterance,
provider,
conversation_id,
execution_mode,
approval_token,
vehicle_id,
simulation_fault,
reasoning_effort,
control_transport,
_local_preview,
_excluded_control_signatures,
_model_parse_source,
_allow_empty_control_result,
_on_commands_validated,
_direct_can_batch,
)
if hardware_access_bypass or self._driver_only_vehicle_execution_active(
control_transport
@@ -1464,6 +1531,7 @@ class SeatDemoService:
_model_parse_source,
_allow_empty_control_result,
_on_commands_validated,
_direct_can_batch,
)
authorized_client_id = self.hardware_access.ensure_authorized(hardware_client_id)
with self.hardware_execution.reserve():
@@ -1483,6 +1551,7 @@ class SeatDemoService:
_model_parse_source,
_allow_empty_control_result,
_on_commands_validated,
_direct_can_batch,
)
def _process_once(
@@ -1501,6 +1570,7 @@ class SeatDemoService:
model_parse_source: str = "cloud_model",
allow_empty_control_result: bool = False,
on_commands_validated: Callable[[dict[str, Any]], None] | None = None,
direct_can_batch: tuple[list[str], dict[str, Any]] | None = None,
) -> dict[str, Any]:
control_transport = self._validate_control_transport(control_transport)
utterance = utterance.strip()
@@ -1569,9 +1639,13 @@ class SeatDemoService:
vehicle_profile,
)
context["mode_profiles"] = self.mode_profiles.public_modes(vehicle_profile.id)
matched_modes = self.mode_profiles.match_text(
utterance,
vehicle_id=vehicle_profile.id,
matched_modes = (
[]
if direct_can_batch is not None
else self.mode_profiles.match_text(
utterance,
vehicle_id=vehicle_profile.id,
)
)
traces: list[dict[str, Any]] = []
result: dict[str, Any] = {
@@ -1614,6 +1688,9 @@ class SeatDemoService:
for item in context.get("presets", [])
],
"trace_events": traces,
"can_commands": (
list(direct_can_batch[0]) if direct_can_batch is not None else []
),
}
started = time.perf_counter()
@@ -1652,40 +1729,45 @@ class SeatDemoService:
result,
traces,
)
parsed, provider_used, provider_notice = self._interpret(
utterance,
provider,
context,
vehicle_profile,
reasoning_effort=reasoning_effort,
local_preview=local_preview,
model_parse_source=model_parse_source,
)
if self._is_dynamic_mode_stop_request(utterance):
parsed = self._apply_dynamic_mode_stop_request(parsed, utterance)
if direct_can_batch is not None:
parsed = deepcopy(direct_can_batch[1])
provider_used = "direct_can_control"
provider_notice = None
else:
parsed = self._apply_mode_profiles(
parsed, matched_modes, context, vehicle_profile
parsed, provider_used, provider_notice = self._interpret(
utterance,
provider,
context,
vehicle_profile,
reasoning_effort=reasoning_effort,
local_preview=local_preview,
model_parse_source=model_parse_source,
)
if self._is_dynamic_mode_stop_request(utterance):
parsed = self._apply_dynamic_mode_stop_request(parsed, utterance)
else:
parsed = self._apply_mode_profiles(
parsed, matched_modes, context, vehicle_profile
)
parsed = self._mark_control_parse_source(parsed, "local_rule")
relative_resolution = (
self.native_can_relative_resolver.resolve(utterance, context)
if self.native_can_relative_resolver.matches(utterance)
else None
)
parsed = merge_native_can_intent(
parsed,
utterance,
relative_actions=(
relative_resolution.actions if relative_resolution else None
),
relative_ambiguities=(
relative_resolution.ambiguities if relative_resolution else None
),
relative_claimed_controls=(
relative_resolution.claimed_controls if relative_resolution else None
),
)
parsed = self._mark_control_parse_source(parsed, "local_rule")
relative_resolution = (
self.native_can_relative_resolver.resolve(utterance, context)
if self.native_can_relative_resolver.matches(utterance)
else None
)
parsed = merge_native_can_intent(
parsed,
utterance,
relative_actions=(
relative_resolution.actions if relative_resolution else None
),
relative_ambiguities=(
relative_resolution.ambiguities if relative_resolution else None
),
relative_claimed_controls=(
relative_resolution.claimed_controls if relative_resolution else None
),
)
if local_preview:
parsed["ambiguities"] = []
parsed["unresolved_spans"] = []
@@ -2136,7 +2218,8 @@ class SeatDemoService:
compile_started = time.perf_counter()
try:
if hardware_request:
self.hardware_settings.validate_function_config(function_config)
if control_transport != WIRELESS_MQTT_TRANSPORT:
self.hardware_settings.validate_function_config(function_config)
command_plan = self.hardware_compiler.compile(
function_config, context["devices"]
)
@@ -2199,7 +2282,11 @@ class SeatDemoService:
"safety_check",
"succeeded",
(
(
"无线 MQTT CAN0 座椅语义白名单与 seat-ota 报文白名单已通过;"
"本地 T2G 固件 profile、USB-CAN 与物理台架连接不参与校验。"
if hardware_request
and control_transport == WIRELESS_MQTT_TRANSPORT
else (
"硬件启用、授权令牌、固件 profile 与目标座椅配置门禁已通过;"
if self.hardware_settings.approval_required
else "硬件启用、调试免令牌、固件 profile 与目标座椅配置门禁已通过;"
@@ -2220,15 +2307,26 @@ class SeatDemoService:
simulation_fault if simulated_hardware_request else None
),
"position_calibration_gate": (
"runtime_can_preflight" if hardware_request else "not_applicable"
"remote_seat_ota_feedback"
if hardware_request
and control_transport == WIRELESS_MQTT_TRANSPORT
else "runtime_can_preflight"
if hardware_request
else "not_applicable"
),
"mapping_status": (
"protocol_hil_verified_combined_firmware_hil_pending"
"mqtt_can0_seat_ota_whitelist"
if hardware_request
and control_transport == WIRELESS_MQTT_TRANSPORT
else "protocol_hil_verified_combined_firmware_hil_pending"
if hardware_request
else "draft"
),
"firmware_profiles": (
sorted(self.hardware_settings.profiles) if hardware_request else []
sorted(self.hardware_settings.profiles)
if hardware_request
and control_transport != WIRELESS_MQTT_TRANSPORT
else []
),
},
)
@@ -2249,9 +2347,6 @@ class SeatDemoService:
command_plan, function_config, context["devices"]
)
if vehicle_safety_preflight is not None:
execution_report["spec"]["vehicle_safety_preflight"] = (
vehicle_safety_preflight
)
for item in execution_report["spec"].get("results", []):
item.setdefault("telemetry", {})[
"vehicle_safety_preflight"
@@ -4045,10 +4140,15 @@ class SeatDemoService:
compile_started = time.perf_counter()
plans: dict[str, dict[str, Any]] = {}
wireless_hardware_request = (
hardware_request
and control_transport == WIRELESS_MQTT_TRANSPORT
)
for domain, config in configs.items():
if domain == "seat":
if hardware_request:
self.hardware_settings.validate_function_config(config)
if not wireless_hardware_request:
self.hardware_settings.validate_function_config(config)
plans[domain] = self.hardware_compiler.compile(
config,
context["devices"],
@@ -4225,13 +4325,10 @@ class SeatDemoService:
"labels": {
"simulation": "mixed" if hardware_request else "true",
"seat_feedback": (
"wireless_mqtt_ch1"
if (
hardware_request
and control_transport == WIRELESS_MQTT_TRANSPORT
and native_config_keys
and "seat" not in configs
)
"wireless_mqtt_ch0"
if wireless_hardware_request and "seat" in configs
else "wireless_mqtt_ch1"
if wireless_hardware_request and native_config_keys
else "physical_can_ch1"
if hardware_request and native_config_keys and "seat" not in configs
else "physical_can"
@@ -4276,13 +4373,9 @@ class SeatDemoService:
"execute",
"succeeded" if execution_succeeded and not report_issues else "failed",
(
"无线 MQTT 白名单控制帧已提交;车辆实际状态以状态话题回读为准。"
if (
hardware_request
and control_transport == WIRELESS_MQTT_TRANSPORT
and native_config_keys
and execution_succeeded
)
"无线 MQTT CAN0/CAN1 白名单控制帧已提交;"
"车辆实际状态以状态话题回读为准。"
if wireless_hardware_request and execution_succeeded
else "CH1 车身 CAN 动作已按目标字段物理回读闭环执行。"
if hardware_request and native_config_keys and execution_succeeded
else "副驾座椅已按独立 T2G 物理 CAN 回读闭环执行。"