fix: execute mode cards through deterministic assistant route
This commit is contained in:
@@ -19,7 +19,7 @@ def test_console_contains_ai_assistant_surface():
|
||||
|
||||
def test_codex_assistant_assets_are_versioned_together_in_the_service_worker():
|
||||
service_worker = (ROOT / "apps/web-console/service-worker.js").read_text(encoding="utf-8")
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v276"' in service_worker
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v277"' in service_worker
|
||||
assert '"/assistant-chat.css?v=codex-assistant-26"' in service_worker
|
||||
assert '"/assistant-chat.js?v=codex-assistant-26"' in service_worker
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from cognitive_agent.application.codex_assistant import (
|
||||
CodexAssistantService,
|
||||
CodexVehicleToolError,
|
||||
_authorize_vehicle_request,
|
||||
_catalog_exact_mode_execution_id,
|
||||
_catalog_exact_mode_match_count,
|
||||
)
|
||||
|
||||
@@ -81,6 +82,60 @@ def test_catalog_mode_resolution_distinguishes_unknown_ambiguous_and_unavailable
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"message",
|
||||
(
|
||||
"进入小憩模式",
|
||||
"请进入小憩模式",
|
||||
"帮我启动午休模式吧",
|
||||
"麻烦帮我执行小憩模式一下",
|
||||
"立即开启小憩模式",
|
||||
"切换到午休模式",
|
||||
),
|
||||
)
|
||||
def test_catalog_resolves_bounded_saved_mode_execution_phrasings(message: str) -> None:
|
||||
catalog = {
|
||||
"modes": [
|
||||
{
|
||||
"id": "nap",
|
||||
"name": "小憩模式",
|
||||
"aliases": ["午休模式"],
|
||||
"assistant_callable": True,
|
||||
}
|
||||
],
|
||||
"source_status": {"modes": "ready"},
|
||||
}
|
||||
|
||||
assert _catalog_exact_mode_execution_id(catalog, message) == "nap"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"message",
|
||||
(
|
||||
"不要进入小憩模式",
|
||||
"小憩模式会执行什么",
|
||||
"能否进入小憩模式?",
|
||||
"进入不存在模式",
|
||||
),
|
||||
)
|
||||
def test_catalog_saved_mode_execution_rejects_denials_questions_and_unknown_modes(
|
||||
message: str,
|
||||
) -> None:
|
||||
catalog = {
|
||||
"modes": [
|
||||
{
|
||||
"id": "nap",
|
||||
"name": "小憩模式",
|
||||
"aliases": ["午休模式"],
|
||||
"assistant_callable": True,
|
||||
}
|
||||
],
|
||||
"source_status": {"modes": "ready"},
|
||||
}
|
||||
|
||||
assert _catalog_exact_mode_execution_id(catalog, message) is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"message",
|
||||
(
|
||||
@@ -402,6 +457,59 @@ def test_general_question_streams_from_codex_without_vehicle_execution() -> None
|
||||
assert client.finished[0].turn_id == "turn-1"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"message",
|
||||
(
|
||||
"进入小憩模式",
|
||||
"请帮我启动午休模式吧",
|
||||
"麻烦执行小憩模式一下",
|
||||
),
|
||||
)
|
||||
def test_registered_mode_execution_uses_fast_local_route_without_codex(
|
||||
message: str,
|
||||
) -> None:
|
||||
client = FakeCodexClient(available=False)
|
||||
assistant = CodexAssistantService(client)
|
||||
calls: list[str] = []
|
||||
catalog = {
|
||||
"modes": [
|
||||
{
|
||||
"id": "nap",
|
||||
"name": "小憩模式",
|
||||
"aliases": ["午休模式"],
|
||||
"assistant_callable": True,
|
||||
}
|
||||
],
|
||||
"source_status": {"modes": "ready"},
|
||||
}
|
||||
|
||||
def execute(instruction: str, progress: Callable[[dict[str, object]], None]):
|
||||
calls.append(instruction)
|
||||
result = _sample_control_result(mode="dry_run")
|
||||
result["utterance"] = instruction
|
||||
progress(result)
|
||||
return result
|
||||
|
||||
result, events = _stream(
|
||||
assistant,
|
||||
message,
|
||||
execute_control=execute,
|
||||
capability_snapshot=catalog,
|
||||
)
|
||||
|
||||
assert result["route"] == "mode_profile_execute"
|
||||
assert result["success"] is True
|
||||
assert calls == [message]
|
||||
assert client.turn_calls == []
|
||||
assert events[0]["engine"] == "n7web-mode-profile-runner"
|
||||
assert events[1]["display_text"] == "正在载入并执行已保存的功能模式……"
|
||||
assert any(
|
||||
event.get("display_text") == "功能模式模拟编排已完成"
|
||||
for event in events
|
||||
)
|
||||
assert "模拟编排" in result["answer"]
|
||||
|
||||
|
||||
def test_registered_name_only_mode_keeps_the_fast_local_route_without_codex() -> None:
|
||||
client = FakeCodexClient(available=False)
|
||||
assistant = CodexAssistantService(client)
|
||||
|
||||
@@ -38,7 +38,7 @@ def test_energy_monitor_assets_are_versioned_and_cached() -> None:
|
||||
assert html.index("/assistant-chat.js?v=codex-assistant-26") < html.index(
|
||||
"/energy-monitor.js?v=energy-monitor-4"
|
||||
)
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v276"' in service_worker
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v277"' in service_worker
|
||||
|
||||
|
||||
def test_energy_monitor_uses_the_fifth_shared_dock_icon_and_starts_closed() -> None:
|
||||
|
||||
@@ -47,7 +47,7 @@ def test_theme_asset_versions_are_consistent_with_the_pwa_shell() -> None:
|
||||
):
|
||||
assert asset in html
|
||||
assert f'"{asset}"' in service_worker
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v276"' in service_worker
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v277"' in service_worker
|
||||
|
||||
|
||||
def test_vehicle_twin_icons_and_nested_overlays_use_semantic_tokens() -> None:
|
||||
|
||||
@@ -271,6 +271,7 @@ const savedMode = {
|
||||
command_flow: { source_request_id: "saved-request" },
|
||||
};
|
||||
const context = {
|
||||
state: { pendingModeProfileId: null },
|
||||
Event: class Event {
|
||||
constructor(type, options = {}) { this.type = type; this.bubbles = options.bubbles; }
|
||||
},
|
||||
@@ -282,6 +283,7 @@ const context = {
|
||||
},
|
||||
modeProfiles() { return [savedMode]; },
|
||||
setModeRailSelection(mode) { calls.push(["select", mode?.id]); },
|
||||
setModeExecutionState(modeId, status) { calls.push(["state", modeId, status]); },
|
||||
closeModeGallery(options) { calls.push(["close", options.restoreFocus]); },
|
||||
showToast(message) { calls.push(["toast", message]); },
|
||||
$(selector) {
|
||||
@@ -295,6 +297,7 @@ console.log(JSON.stringify({
|
||||
calls,
|
||||
value: input.value,
|
||||
speechDataset: input.dataset,
|
||||
pendingModeProfileId: context.state.pendingModeProfileId,
|
||||
}));
|
||||
"""
|
||||
completed = subprocess.run(
|
||||
@@ -312,10 +315,12 @@ console.log(JSON.stringify({
|
||||
["close", False],
|
||||
["open"],
|
||||
["input", "input", True, "进入阅读模式"],
|
||||
["state", "reading-user", "running"],
|
||||
["submit", "进入阅读模式"],
|
||||
]
|
||||
assert result["value"] == "进入阅读模式"
|
||||
assert result["speechDataset"] == {}
|
||||
assert result["pendingModeProfileId"] == "reading-user"
|
||||
assert "executeSavedModeProfile" not in snippet
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user