fix: harden conversational mode draft revisions
This commit is contained in:
@@ -983,6 +983,22 @@ class CodexAssistantService:
|
||||
if draft.get("existing_mode_id")
|
||||
else "确认后可保存为功能模式。"
|
||||
)
|
||||
requested_operation_count = draft.get("requested_operation_count")
|
||||
changed_operation_count = draft.get("changed_operation_count")
|
||||
no_effective_change = (
|
||||
isinstance(requested_operation_count, int)
|
||||
and not isinstance(requested_operation_count, bool)
|
||||
and requested_operation_count > 0
|
||||
and isinstance(changed_operation_count, int)
|
||||
and not isinstance(changed_operation_count, bool)
|
||||
and changed_operation_count == 0
|
||||
)
|
||||
if no_effective_change:
|
||||
return (
|
||||
f"待保存的“{name}”模式中,该项原本已是目标状态,"
|
||||
f"已保持不变并重新校验全部{operation_count}项组合动作。"
|
||||
f"原草稿未被保存或执行,可以继续调整;{persistence_hint}"
|
||||
)
|
||||
return (
|
||||
f"已调整待保存的“{name}”模式,并重新校验全部"
|
||||
f"{operation_count}项组合动作。原草稿未被保存或执行,"
|
||||
@@ -1839,6 +1855,8 @@ class CodexAssistantService:
|
||||
"generation_source",
|
||||
"draft_revision",
|
||||
"revises_source_request_id",
|
||||
"requested_operation_count",
|
||||
"changed_operation_count",
|
||||
)
|
||||
if key in mode_profile_draft
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ _CONTEXTUAL_NAME_FIRST_UPDATE = re.compile(
|
||||
r"(?P<change>.+?)[。.!!]?$"
|
||||
)
|
||||
MODE_PROFILE_CHANGE_PREDICATE = re.compile(
|
||||
r"修改|改成|改为|更改|更新|变更|变为|换成|"
|
||||
r"修改|改成|改为|更改|更新|变更|变成|变为|换成|"
|
||||
r"调整|调节|调高|调低|调到|调成|调为|调至|"
|
||||
r"设置|设为|设成|设到|设至|"
|
||||
r"打开|开启|启动|关闭|关掉|关上|全关|停止|停用|切换|进入|退出|"
|
||||
@@ -40,7 +40,7 @@ MODE_PROFILE_QUERY_CUE = re.compile(
|
||||
r"什么|哪些|多少|几(?:度|档|级|个|项)?|是否|是不是|"
|
||||
r"合适(?:吗)?|合理(?:吗)?|会(?:怎么样|怎样|如何)|"
|
||||
r"怎么|如何|列(?:出|一下)|介绍(?:一下)?|说明(?:一下)?|"
|
||||
r"告诉我|查询|查看|有什么作用|是何作用|还是|[??]"
|
||||
r"告诉我|查询|查看|有什么作用|是何作用|还是|[??]|(?:吗|么|呢)$"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1349,7 +1349,8 @@ def _parse_chinese_commands(text: str) -> list[dict[str, Any]]:
|
||||
shade_text = _scoped_text(compact, r"遮阳帘|天幕帘")
|
||||
if shade_text and _allows_vehicle_wide_target(shade_text):
|
||||
position = re.search(
|
||||
r"(?:位置|开度|调整到|调到|设为|设置为|开到|打开(?:到)?|开启(?:到)?)(\d{1,3})%",
|
||||
r"(?:位置|开度|调整到|调整为|调到|调为|改为|改成|变为|变成|"
|
||||
r"换成|设为|设置为|开到|打开(?:到)?|开启(?:到)?)(\d{1,3})%",
|
||||
shade_text,
|
||||
)
|
||||
if position and int(position[1]) <= 100:
|
||||
|
||||
@@ -4309,7 +4309,7 @@ class SeatDemoService:
|
||||
if not change_text:
|
||||
raise ValueError("请说明要调整的设备和明确目标值。")
|
||||
parseable_change_text = re.sub(
|
||||
r"改为|改成|变更为|换成|变为",
|
||||
r"改为|改成|变更为|换成|变成|变为",
|
||||
"调整为",
|
||||
change_text,
|
||||
)
|
||||
@@ -4387,6 +4387,22 @@ class SeatDemoService:
|
||||
): item
|
||||
for item in normalized_changes
|
||||
}
|
||||
base_by_key = {
|
||||
(
|
||||
str(item["domain"]),
|
||||
str(item["capability"]),
|
||||
str(item["target_scope"]),
|
||||
): item
|
||||
for item in base_operations
|
||||
}
|
||||
requested_operation_count = len(change_by_key)
|
||||
changed_operation_count = sum(
|
||||
1
|
||||
for key, item in change_by_key.items()
|
||||
if key not in base_by_key
|
||||
or dict(base_by_key[key].get("parameters") or {})
|
||||
!= dict(item.get("parameters") or {})
|
||||
)
|
||||
merged: list[dict[str, Any]] = []
|
||||
for operation in base_operations:
|
||||
key = (
|
||||
@@ -4397,7 +4413,7 @@ class SeatDemoService:
|
||||
merged.append(deepcopy(change_by_key.pop(key, operation)))
|
||||
merged.extend(deepcopy(list(change_by_key.values())))
|
||||
|
||||
return self._process_mode_profile_create(
|
||||
revised_result = self._process_mode_profile_create(
|
||||
utterance,
|
||||
"local",
|
||||
conversation_id,
|
||||
@@ -4410,6 +4426,26 @@ class SeatDemoService:
|
||||
assistant_plan=self._mode_profile_draft_plan(merged),
|
||||
source_draft=source_draft,
|
||||
)
|
||||
revised_draft = revised_result.get("mode_profile_draft")
|
||||
if (
|
||||
revised_result.get("status") == "succeeded"
|
||||
and isinstance(revised_draft, dict)
|
||||
and revised_draft.get("generation_source") == "draft_revision"
|
||||
):
|
||||
revised_draft["requested_operation_count"] = (
|
||||
requested_operation_count
|
||||
)
|
||||
revised_draft["changed_operation_count"] = changed_operation_count
|
||||
mode_creation = revised_result.get("mode_creation")
|
||||
if isinstance(mode_creation, dict):
|
||||
mode_creation["requested_operation_count"] = (
|
||||
requested_operation_count
|
||||
)
|
||||
mode_creation["changed_operation_count"] = (
|
||||
changed_operation_count
|
||||
)
|
||||
self._persist(revised_result)
|
||||
return revised_result
|
||||
except ValueError as exc:
|
||||
result["status"] = "needs_confirmation"
|
||||
result["execution_mode"] = "dry_run"
|
||||
@@ -7180,7 +7216,21 @@ class SeatDemoService:
|
||||
allow_scene_composition: bool = False,
|
||||
) -> tuple[dict[str, Any], str, str | None]:
|
||||
vehicle_profile = vehicle_profile or self.vehicle_profiles.default()
|
||||
clause_results = self._local_clause_results(utterance, context)
|
||||
if assistant_plan is not None and allow_scene_composition:
|
||||
# ``utterance`` is a synthesized ``进入<mode name>`` carrier for a
|
||||
# name-only scene (and for a server-owned draft revision). Words
|
||||
# inside that label are not user-authored atomic instructions:
|
||||
# e.g. ``外循环通风模式`` previously leaked ``通风`` into the seat
|
||||
# parser and added an AMBIGUOUS_INTENT beside an otherwise valid
|
||||
# climate plan. In this narrow path the complete assistant plan is
|
||||
# the candidate source of actions; it still passes the scene
|
||||
# allowlist, registered capability contract, ModelPlanAdapter,
|
||||
# schema/safety validation and native compiler below.
|
||||
clause_results = [
|
||||
(utterance, self._merge_parsed_results([]), "unparsed")
|
||||
]
|
||||
else:
|
||||
clause_results = self._local_clause_results(utterance, context)
|
||||
|
||||
trusted_local = self._merge_parsed_results(
|
||||
[parsed for _, parsed, status in clause_results if status != "unparsed"]
|
||||
|
||||
Reference in New Issue
Block a user