feat: add seat-scoped static and dynamic assistant modes

This commit is contained in:
vee
2026-09-12 14:56:30 +08:00
parent d09b5967f8
commit d8dad22ec0
60 changed files with 5847 additions and 149 deletions
@@ -12,6 +12,8 @@ from typing import Any
import yaml
from cognitive_agent.application.mode_schedule import ModeSchedule
_MATCH_FORMATTING = re.compile(r"[\s()()]+")
_NON_ASCII_SLUG = re.compile(r"[^a-z0-9]+")
_MODE_ID = re.compile(r"^[a-z0-9][a-z0-9_-]{0,63}$")
@@ -450,6 +452,7 @@ class ModeProfile:
user_defined: bool = False
instruction: str = ""
command_flow: dict[str, Any] | None = None
schedule: ModeSchedule | None = None
@classmethod
def from_yaml(cls, path: Path, profile_root: Path | None = None) -> "ModeProfile":
@@ -486,10 +489,12 @@ class ModeProfile:
user_defined=_is_user_profile_path(path, profile_root),
instruction=_clean_instruction(document.get("instruction", "")),
command_flow=_clean_command_flow(document.get("command_flow")),
schedule=(ModeSchedule.from_dict(document["schedule"])
if document.get("schedule") is not None else None),
)
def public_dict(self) -> dict[str, Any]:
is_cyclic = self.timeline is not None or any(
is_cyclic = self.schedule is not None or self.timeline is not None or any(
operation.capability == "seat.start_dynamic_mode"
for operation in self.operations
)
@@ -514,6 +519,9 @@ class ModeProfile:
}
if self.timeline is not None:
result["timeline"] = self.timeline.public_dict()
if self.schedule is not None:
result["schedule"] = self.schedule.to_dict()
result["operation_count"] = self.schedule.operation_count
return result
@@ -656,6 +664,7 @@ class ModeProfileRegistry:
},
"operations": [operation.to_yaml() for operation in profile.operations],
"timeline": profile.timeline.to_yaml() if profile.timeline is not None else None,
"schedule": profile.schedule.to_dict() if profile.schedule is not None else None,
"instruction": profile.instruction,
"command_flow": profile.command_flow,
}
@@ -688,6 +697,7 @@ class ModeProfileRegistry:
instruction: str = "",
command_flow: dict[str, Any] | None = None,
timeline: ModeTimeline | None = None,
schedule: ModeSchedule | None = None,
expected_revision: str | None = None,
create_only: bool = False,
) -> ModeProfile:
@@ -725,6 +735,8 @@ class ModeProfileRegistry:
document["command_flow"] = clean_command_flow
if timeline is not None:
document["timeline"] = timeline.to_yaml()
if schedule is not None:
document["schedule"] = schedule.to_dict()
path = (
self.user_root / "vehicles" / vehicle_id / "user" / f"{profile_id}.yaml"
if vehicle_id
@@ -994,6 +1006,8 @@ def _mode_profile_document(
}
if profile.timeline is not None:
document["timeline"] = profile.timeline.to_yaml()
if profile.schedule is not None:
document["schedule"] = profile.schedule.to_dict()
if profile.instruction:
document["instruction"] = profile.instruction
if profile.command_flow is not None: