merge: integrate remote MQTT routing with seat-scoped dynamic modes
This commit is contained in:
@@ -66,6 +66,12 @@ from cognitive_agent.application.mode_profile_intent import ( # noqa: E402
|
||||
parse_mode_profile_delete,
|
||||
parse_mode_profile_update,
|
||||
)
|
||||
from cognitive_agent.application.mode_scene_catalog import ( # noqa: E402
|
||||
DEFAULT_N7_SCENE_SERVER_ID,
|
||||
DEFAULT_N7_SCENE_SERVER_NAME,
|
||||
ModeSceneCatalogPublisher,
|
||||
build_mode_scene_catalog,
|
||||
)
|
||||
from cognitive_agent.application.mode_schedule import ModeSchedule, ModeScheduleRunner # noqa: E402
|
||||
from cognitive_agent.application.mode_schedule_service import ModeScheduleServiceMixin # noqa: E402
|
||||
from cognitive_agent.application.model_plan_adapter import ( # noqa: E402
|
||||
@@ -179,6 +185,7 @@ MODE_PROFILE_UPDATE_EXPLICIT_TARGET_PATTERN = re.compile(
|
||||
)
|
||||
WIRED_CAN_TRANSPORT = "wired_can"
|
||||
WIRELESS_MQTT_TRANSPORT = "wireless_mqtt"
|
||||
LOCAL_CONTROL_BUDGET_MS = 1000
|
||||
VEHICLE_CONTROL_TRANSPORTS = frozenset(
|
||||
{WIRED_CAN_TRANSPORT, WIRELESS_MQTT_TRANSPORT}
|
||||
)
|
||||
@@ -300,6 +307,7 @@ CONTROL_CLAUSE_SUBJECT_PATTERN = re.compile(
|
||||
r"座椅|座位|靠背|椅背|坐盆|坐垫|腿托|脚托|滑轨|"
|
||||
r"通风|加热|按摩|零重力|半躺|女王副驾|休闲躺椅|"
|
||||
r"遮阳帘|天幕帘|天幕|车窗|窗户|"
|
||||
r"(?:左前|前左|右前|前右|左后|后左|右后|后右)(?:排)?窗|"
|
||||
r"灯光|室内灯|车内灯|阅读灯|氛围灯|"
|
||||
r"空调|压缩机|温度|风量|风速|内循环|外循环|"
|
||||
r"车门|门锁|后备箱|前大灯|近光灯|远光灯|雾灯|转向灯|双闪|"
|
||||
@@ -310,10 +318,17 @@ CONTROL_CLAUSE_PREDICATE_PATTERN = re.compile(
|
||||
r"调整|调节|调到|调成|调为|调至|设置|设为|设到|切换|"
|
||||
r"移动|移到|移至|前移|后移|上移|下移|升高|降低|抬起|放倒|"
|
||||
r"调直|立直|竖直|归零|复位|锁上|上锁|落锁|解锁|"
|
||||
r"零重力|半躺|最大|最小|最高|最低|最前|最后|到底|"
|
||||
r"零重力|半躺|一半|半开|半关|最大|最小|最高|最低|最前|最后|到底|"
|
||||
r"(?:\d+(?:\.\d+)?|[零一二三四五六七八九十百两半]+)"
|
||||
r"(?:%|%|度|℃|档|级|秒|毫秒)"
|
||||
)
|
||||
# These verbs identify an independent request that may be outside the local
|
||||
# vehicle registry. They are used only to split mixed sentences so an
|
||||
# already deterministic clause never has to be repeated to a hosted model.
|
||||
CLOUD_REQUEST_CLAUSE_PATTERN = re.compile(
|
||||
r"播放|暂停播放|停止播放|导航|搜索|查找|查询|拨打|呼叫|发送|"
|
||||
r"提醒|推荐|讲解|介绍|告诉|规划"
|
||||
)
|
||||
RESTORE_MODE_PROFILE_PREFIX = re.compile(
|
||||
r"^(?:请(?:帮我)?|帮我)?(?:恢复|还原|重置|初始化)"
|
||||
r"(?P<name>[^,。,.!!\s]{1,64}?模式)"
|
||||
@@ -429,6 +444,17 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
repository_root / "config" / "modes",
|
||||
user_root=self.mode_profile_user_root,
|
||||
)
|
||||
self._mode_scene_catalog_publisher: ModeSceneCatalogPublisher | None = None
|
||||
self._mode_scene_catalog_status: dict[str, Any] = {
|
||||
"enabled": False,
|
||||
"state": "disabled",
|
||||
"path": None,
|
||||
"vehicle_id": self.vehicle_profiles.default().id,
|
||||
"server_id": DEFAULT_N7_SCENE_SERVER_ID,
|
||||
"catalog_revision": None,
|
||||
"scene_count": 0,
|
||||
"last_error": None,
|
||||
}
|
||||
self.scene_templates = SceneTemplateRegistry(
|
||||
repository_root / "config" / "scene_templates"
|
||||
)
|
||||
@@ -447,6 +473,88 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
if hasattr(self, "conversations"):
|
||||
self.conversations.preset_root = self._artifact_root / "user-presets"
|
||||
|
||||
def configure_mode_scene_catalog(
|
||||
self,
|
||||
path: Path,
|
||||
*,
|
||||
server_id: str = DEFAULT_N7_SCENE_SERVER_ID,
|
||||
name: str = DEFAULT_N7_SCENE_SERVER_NAME,
|
||||
) -> dict[str, Any]:
|
||||
"""Enable the derived JSON catalog without changing YAML persistence."""
|
||||
|
||||
catalog_path = Path(path).expanduser()
|
||||
if not catalog_path.is_absolute():
|
||||
catalog_path = self.root / catalog_path
|
||||
vehicle_id = self.vehicle_profiles.default().id
|
||||
self._mode_scene_catalog_publisher = ModeSceneCatalogPublisher(
|
||||
catalog_path,
|
||||
vehicle_id,
|
||||
server_id=server_id,
|
||||
name=name,
|
||||
)
|
||||
self._mode_scene_catalog_status = {
|
||||
"enabled": True,
|
||||
"state": "initializing",
|
||||
"path": str(catalog_path),
|
||||
"vehicle_id": vehicle_id,
|
||||
"server_id": self._mode_scene_catalog_publisher.server_id,
|
||||
"catalog_revision": None,
|
||||
"scene_count": 0,
|
||||
"last_error": None,
|
||||
}
|
||||
# The registry notifies after create, update, delete, restore, and any
|
||||
# explicit reload. The callback only updates a derived projection; YAML
|
||||
# remains the authoritative store used by every existing execution path.
|
||||
self.mode_profiles.add_change_listener(self._synchronize_mode_scene_catalog)
|
||||
return self.mode_scene_catalog_status()
|
||||
|
||||
def _synchronize_mode_scene_catalog(self, registry: ModeProfileRegistry) -> None:
|
||||
publisher = self._mode_scene_catalog_publisher
|
||||
if publisher is None:
|
||||
return
|
||||
try:
|
||||
catalog = publisher.publish(registry)
|
||||
except Exception as exc: # noqa: BLE001 - derived export must not block controls
|
||||
self._mode_scene_catalog_status.update(
|
||||
{
|
||||
"state": "error",
|
||||
"last_error": str(exc),
|
||||
}
|
||||
)
|
||||
return
|
||||
self._mode_scene_catalog_status.update(
|
||||
{
|
||||
"state": "ready",
|
||||
"catalog_revision": catalog["catalog_revision"],
|
||||
"scene_count": catalog["scene_count"],
|
||||
"last_error": None,
|
||||
}
|
||||
)
|
||||
|
||||
def mode_scene_catalog(self, vehicle_id: str | None = None) -> dict[str, Any]:
|
||||
"""Return the current read-only mode-card catalog for an N7 client."""
|
||||
|
||||
resolved_vehicle_id = vehicle_id or self.vehicle_profiles.default().id
|
||||
publisher = self._mode_scene_catalog_publisher
|
||||
if publisher is not None and resolved_vehicle_id == publisher.vehicle_id:
|
||||
self._synchronize_mode_scene_catalog(self.mode_profiles)
|
||||
snapshot = publisher.snapshot()
|
||||
if snapshot is not None and self._mode_scene_catalog_status["state"] == "ready":
|
||||
return snapshot
|
||||
return build_mode_scene_catalog(
|
||||
self.mode_profiles,
|
||||
resolved_vehicle_id,
|
||||
server_id=(
|
||||
publisher.server_id
|
||||
if publisher is not None
|
||||
else DEFAULT_N7_SCENE_SERVER_ID
|
||||
),
|
||||
name=(publisher.name if publisher is not None else DEFAULT_N7_SCENE_SERVER_NAME),
|
||||
)
|
||||
|
||||
def mode_scene_catalog_status(self) -> dict[str, Any]:
|
||||
return deepcopy(self._mode_scene_catalog_status)
|
||||
|
||||
@property
|
||||
def driver_only_ch1_execution_active(self) -> bool:
|
||||
"""Return whether deployment policy authorizes only the CH1 vehicle path."""
|
||||
@@ -603,6 +711,7 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
"scene_templates": self.scene_templates.public_templates(),
|
||||
"mode_profile_storage": "persistent_yaml",
|
||||
"mode_profile_user_root": str(self.mode_profile_user_root),
|
||||
"mode_scene_catalog": self.mode_scene_catalog_status(),
|
||||
"preset_storage": "conversation_durable",
|
||||
"inferred_level_range": [1, 3],
|
||||
"motion_position_range_pct": [0, 100],
|
||||
@@ -1545,9 +1654,11 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
on_commands_validated: Callable[[dict[str, Any]], None] | None = None,
|
||||
assistant_plan: dict[str, Any] | None = None,
|
||||
mode_profile_draft_context: dict[str, Any] | None = None,
|
||||
_cloud_instruction_context: dict[str, Any] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Validate and execute deterministic controls before hosted parsing."""
|
||||
|
||||
local_stage_started = time.perf_counter()
|
||||
utterance = utterance.strip()
|
||||
if not utterance:
|
||||
raise ValueError("utterance must not be empty")
|
||||
@@ -1576,6 +1687,7 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
_on_commands_validated=on_commands_validated,
|
||||
_assistant_plan=assistant_plan,
|
||||
_mode_profile_draft_context=mode_profile_draft_context,
|
||||
_cloud_instruction_context=_cloud_instruction_context,
|
||||
)
|
||||
result.update(
|
||||
{
|
||||
@@ -1594,14 +1706,71 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
vehicle_profile,
|
||||
)
|
||||
clause_results = self._local_clause_results(utterance, context)
|
||||
unresolved_clauses = [
|
||||
locally_parsed_clauses = [
|
||||
clause
|
||||
for clause, _, status in clause_results
|
||||
if status != "unparsed"
|
||||
]
|
||||
locally_resolved_clauses = [
|
||||
clause
|
||||
for clause, _, status in clause_results
|
||||
if status == "complete"
|
||||
]
|
||||
locally_unresolved_clauses = [
|
||||
clause
|
||||
for clause, _, status in clause_results
|
||||
if status != "complete"
|
||||
]
|
||||
started = time.perf_counter()
|
||||
supplied_routing = (
|
||||
_cloud_instruction_context
|
||||
if isinstance(_cloud_instruction_context, dict)
|
||||
else {}
|
||||
)
|
||||
|
||||
def routing_clauses(key: str) -> list[str]:
|
||||
raw = supplied_routing.get(key)
|
||||
if not isinstance(raw, list):
|
||||
return []
|
||||
return [
|
||||
text
|
||||
for item in raw[:64]
|
||||
for text in [str(item).strip()[:1000]]
|
||||
if text
|
||||
]
|
||||
|
||||
def unique_clauses(*groups: list[str]) -> list[str]:
|
||||
return list(dict.fromkeys(item for group in groups for item in group))
|
||||
|
||||
parsed_clauses = unique_clauses(
|
||||
routing_clauses("parsed_clauses"),
|
||||
locally_parsed_clauses,
|
||||
)
|
||||
resolved_clauses = unique_clauses(
|
||||
routing_clauses("resolved_clauses"),
|
||||
locally_resolved_clauses,
|
||||
)
|
||||
unresolved_clauses = locally_unresolved_clauses
|
||||
routing_unresolved_clauses = unique_clauses(
|
||||
routing_clauses("unresolved_clauses"),
|
||||
locally_unresolved_clauses,
|
||||
)
|
||||
original_utterance = str(
|
||||
supplied_routing.get("original_utterance") or utterance
|
||||
).strip()[:1000]
|
||||
natural_language_routing = {
|
||||
"original_utterance": original_utterance,
|
||||
"parsed_clauses": parsed_clauses,
|
||||
"resolved_clauses": resolved_clauses,
|
||||
"unresolved_clauses": routing_unresolved_clauses,
|
||||
}
|
||||
local_dispatch_elapsed_ms: float | None = None
|
||||
|
||||
def publish_local_commands(validated: dict[str, Any]) -> None:
|
||||
nonlocal local_dispatch_elapsed_ms
|
||||
local_dispatch_elapsed_ms = round(
|
||||
(time.perf_counter() - local_stage_started) * 1000,
|
||||
3,
|
||||
)
|
||||
if on_commands_validated is None:
|
||||
return
|
||||
event = deepcopy(validated)
|
||||
@@ -1613,6 +1782,14 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
"supplement_required": bool(
|
||||
provider != "local" and unresolved_clauses
|
||||
),
|
||||
"natural_language_routing": deepcopy(
|
||||
natural_language_routing
|
||||
),
|
||||
"local_control_budget_ms": LOCAL_CONTROL_BUDGET_MS,
|
||||
"local_control_elapsed_ms": local_dispatch_elapsed_ms,
|
||||
"local_control_within_budget": (
|
||||
local_dispatch_elapsed_ms < LOCAL_CONTROL_BUDGET_MS
|
||||
),
|
||||
}
|
||||
)
|
||||
on_commands_validated(event)
|
||||
@@ -1634,8 +1811,17 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
_on_commands_validated=publish_local_commands,
|
||||
_assistant_plan=assistant_plan,
|
||||
_mode_profile_draft_context=mode_profile_draft_context,
|
||||
_cloud_instruction_context=natural_language_routing,
|
||||
)
|
||||
elapsed_ms = round(
|
||||
(time.perf_counter() - local_stage_started) * 1000,
|
||||
3,
|
||||
)
|
||||
local_control_elapsed_ms = (
|
||||
local_dispatch_elapsed_ms
|
||||
if local_dispatch_elapsed_ms is not None
|
||||
else elapsed_ms
|
||||
)
|
||||
elapsed_ms = round((time.perf_counter() - started) * 1000, 3)
|
||||
supplement_required = bool(
|
||||
provider != "local" and unresolved_clauses
|
||||
)
|
||||
@@ -1645,7 +1831,17 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
"provider_requested": provider,
|
||||
"preview_request_id": result["request_id"],
|
||||
"preview_elapsed_ms": elapsed_ms,
|
||||
"local_control_budget_ms": LOCAL_CONTROL_BUDGET_MS,
|
||||
"local_control_elapsed_ms": local_control_elapsed_ms,
|
||||
"local_control_within_budget": (
|
||||
local_control_elapsed_ms < LOCAL_CONTROL_BUDGET_MS
|
||||
),
|
||||
"parsed_clauses": parsed_clauses,
|
||||
"resolved_clauses": resolved_clauses,
|
||||
"unresolved_clauses": unresolved_clauses,
|
||||
"natural_language_routing": deepcopy(
|
||||
natural_language_routing
|
||||
),
|
||||
"supplement_required": supplement_required,
|
||||
}
|
||||
)
|
||||
@@ -1669,7 +1865,10 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
"hardware_client_id": hardware_client_id,
|
||||
"reasoning_effort": reasoning_effort,
|
||||
"control_transport": control_transport,
|
||||
"parsed_clauses": parsed_clauses,
|
||||
"resolved_clauses": resolved_clauses,
|
||||
"unresolved_clauses": unresolved_clauses,
|
||||
"natural_language_routing": natural_language_routing,
|
||||
"preview_control_signatures": result.get(
|
||||
"parsed_control_signatures", []
|
||||
),
|
||||
@@ -1734,6 +1933,34 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
for item in manifest.get("preview_control_signatures", [])
|
||||
if isinstance(item, list)
|
||||
}
|
||||
manifest_routing = manifest.get("natural_language_routing")
|
||||
natural_language_routing = (
|
||||
deepcopy(manifest_routing)
|
||||
if isinstance(manifest_routing, dict)
|
||||
else {
|
||||
"original_utterance": str(manifest.get("utterance") or ""),
|
||||
"parsed_clauses": list(manifest.get("parsed_clauses") or []),
|
||||
"resolved_clauses": list(manifest.get("resolved_clauses") or []),
|
||||
"unresolved_clauses": unresolved_clauses,
|
||||
}
|
||||
)
|
||||
routing_unresolved = natural_language_routing.get("unresolved_clauses")
|
||||
natural_language_routing["unresolved_clauses"] = list(
|
||||
dict.fromkeys(
|
||||
[
|
||||
str(item).strip()
|
||||
for item in (
|
||||
routing_unresolved
|
||||
if isinstance(routing_unresolved, list)
|
||||
else []
|
||||
)
|
||||
if str(item).strip()
|
||||
]
|
||||
+ unresolved_clauses
|
||||
)
|
||||
)
|
||||
cloud_utterance = ",".join(unresolved_clauses)
|
||||
natural_language_routing["cloud_input_utterance"] = cloud_utterance
|
||||
|
||||
def publish_cloud_commands(validated: dict[str, Any]) -> None:
|
||||
if on_commands_validated is None:
|
||||
@@ -1750,7 +1977,7 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
on_commands_validated(event)
|
||||
|
||||
supplement = self.process(
|
||||
",".join(unresolved_clauses),
|
||||
cloud_utterance,
|
||||
provider=selected_provider,
|
||||
conversation_id=str(manifest["conversation_id"]),
|
||||
execution_mode=str(manifest.get("execution_mode") or "dry_run"),
|
||||
@@ -1769,6 +1996,7 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
_model_parse_source="cloud_supplement",
|
||||
_allow_empty_control_result=True,
|
||||
_on_commands_validated=publish_cloud_commands,
|
||||
_cloud_instruction_context=natural_language_routing,
|
||||
)
|
||||
merged = self._merge_native_can_phases(preview, supplement)
|
||||
merged.update(
|
||||
@@ -1785,6 +2013,7 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
"supplement_request_id": supplement["request_id"],
|
||||
"supplement_required": False,
|
||||
"unresolved_clauses": unresolved_clauses,
|
||||
"natural_language_routing": natural_language_routing,
|
||||
}
|
||||
)
|
||||
self._persist(merged)
|
||||
@@ -2081,6 +2310,7 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
_speech_understanding: dict[str, Any] | None = None,
|
||||
_assistant_plan: dict[str, Any] | None = None,
|
||||
_mode_profile_draft_context: dict[str, Any] | None = None,
|
||||
_cloud_instruction_context: 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
|
||||
@@ -2155,6 +2385,7 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
_speech_understanding,
|
||||
assistant_plan=_assistant_plan,
|
||||
mode_profile_draft_context=_mode_profile_draft_context,
|
||||
cloud_instruction_context=_cloud_instruction_context,
|
||||
)
|
||||
if control_transport == WIRELESS_MQTT_TRANSPORT:
|
||||
# The head unit owns both physical CAN channels in wireless mode.
|
||||
@@ -2180,6 +2411,7 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
_speech_understanding,
|
||||
assistant_plan=_assistant_plan,
|
||||
mode_profile_draft_context=_mode_profile_draft_context,
|
||||
cloud_instruction_context=_cloud_instruction_context,
|
||||
)
|
||||
if hardware_access_bypass or self._driver_only_vehicle_execution_active(
|
||||
control_transport
|
||||
@@ -2205,6 +2437,7 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
_speech_understanding,
|
||||
assistant_plan=_assistant_plan,
|
||||
mode_profile_draft_context=_mode_profile_draft_context,
|
||||
cloud_instruction_context=_cloud_instruction_context,
|
||||
)
|
||||
authorized_client_id = self.hardware_access.ensure_authorized(hardware_client_id)
|
||||
with self.hardware_execution.reserve():
|
||||
@@ -2229,6 +2462,7 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
_speech_understanding,
|
||||
assistant_plan=_assistant_plan,
|
||||
mode_profile_draft_context=_mode_profile_draft_context,
|
||||
cloud_instruction_context=_cloud_instruction_context,
|
||||
)
|
||||
|
||||
def _process_once(
|
||||
@@ -2256,6 +2490,7 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
scene_scope_utterance: str | None = None,
|
||||
mode_creation_scopes: frozenset[str] | None = None,
|
||||
mode_profile_draft_context: dict[str, Any] | None = None,
|
||||
cloud_instruction_context: dict[str, Any] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
control_transport = self._validate_control_transport(control_transport)
|
||||
utterance = utterance.strip()
|
||||
@@ -2589,6 +2824,7 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
assistant_plan=assistant_plan,
|
||||
allow_scene_composition=allow_scene_composition,
|
||||
scene_scope_utterance=scene_scope_utterance,
|
||||
cloud_instruction_context=cloud_instruction_context,
|
||||
)
|
||||
scene_label_only = assistant_plan is not None and allow_scene_composition
|
||||
dynamic_mode_stop = (
|
||||
@@ -7450,6 +7686,11 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
and CONTROL_CLAUSE_PREDICATE_PATTERN.search(value)
|
||||
)
|
||||
|
||||
def looks_like_independent_request(value: str) -> bool:
|
||||
return looks_like_control(value) or bool(
|
||||
CLOUD_REQUEST_CLAUSE_PATTERN.search(value)
|
||||
)
|
||||
|
||||
def split_independent_controls(
|
||||
value: str,
|
||||
separator_pattern: str,
|
||||
@@ -7460,7 +7701,14 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
for index in range(1, len(tokens), 2):
|
||||
separator = tokens[index]
|
||||
next_item = tokens[index + 1].strip()
|
||||
if looks_like_control(current) and looks_like_control(next_item):
|
||||
if (
|
||||
looks_like_independent_request(current)
|
||||
and looks_like_independent_request(next_item)
|
||||
and (
|
||||
looks_like_control(current)
|
||||
or looks_like_control(next_item)
|
||||
)
|
||||
):
|
||||
if current:
|
||||
separated.append(current)
|
||||
current = next_item
|
||||
@@ -7771,6 +8019,7 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
assistant_plan: dict[str, Any] | None = None,
|
||||
allow_scene_composition: bool = False,
|
||||
scene_scope_utterance: str | None = None,
|
||||
cloud_instruction_context: dict[str, Any] | None = None,
|
||||
) -> tuple[dict[str, Any], str, str | None]:
|
||||
vehicle_profile = vehicle_profile or self.vehicle_profiles.default()
|
||||
if assistant_plan is not None and allow_scene_composition:
|
||||
@@ -7936,9 +8185,29 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
interpret_options = {}
|
||||
if reasoning_effort is not None:
|
||||
interpret_options["reasoning_effort"] = reasoning_effort
|
||||
hosted_context = deepcopy(context)
|
||||
if isinstance(cloud_instruction_context, dict):
|
||||
routing_context = deepcopy(cloud_instruction_context)
|
||||
else:
|
||||
routing_context = {
|
||||
"original_utterance": utterance,
|
||||
"parsed_clauses": [
|
||||
clause
|
||||
for clause, _, status in clause_results
|
||||
if status != "unparsed"
|
||||
],
|
||||
"resolved_clauses": [
|
||||
clause
|
||||
for clause, _, status in clause_results
|
||||
if status == "complete"
|
||||
],
|
||||
"unresolved_clauses": fallback_clauses,
|
||||
}
|
||||
routing_context["cloud_input_utterance"] = fallback_utterance
|
||||
hosted_context["natural_language_routing"] = routing_context
|
||||
plan = self.openai.interpret(
|
||||
fallback_utterance,
|
||||
context,
|
||||
hosted_context,
|
||||
self.capability_context,
|
||||
**interpret_options,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user