Files
Cognitive_Agent/tests/unit/test_scene_composer_fast_path.py
T

1550 lines
52 KiB
Python

from __future__ import annotations
import json
import queue
import threading
import time
from collections.abc import Callable, Mapping
from concurrent.futures import ThreadPoolExecutor
from copy import deepcopy
import pytest
from cognitive_agent.application.codex_assistant import (
ActiveCodexTurn,
CodexAssistantService,
_mode_profile_create_parts,
)
CONTROL_TERMS = ("空调", "座椅", "车窗", "遮阳帘", "氛围灯", "阅读灯", "出风口")
@pytest.mark.parametrize(("message", "mode_name"), [
("构建一个观影模式", "观影模式"),
("为主驾构建一个观影模式", "主驾观影模式"),
])
def test_local_first_callbacks_do_not_intercept_scoped_mode_draft_creation(message, mode_name):
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
events = []
control_calls = []
def execute_control(instruction, _progress, plan):
control_calls.append((instruction, plan))
return _preview_result(mode_name)
result = assistant.stream(
message, conversation_id="conv-merged-scene-router", principal="test",
history=[], emit=events.append, execute_control=execute_control,
preview_control=lambda *_args: pytest.fail("mode previews must not partially execute via local-first controls"),
supplement_control=lambda *_args: pytest.fail("mode previews must not become unresolved control supplements"),
control_terms=CONTROL_TERMS,
capability_snapshot=_catalog_with_templates(_scene_template()),
scene_capability_context=_scene_context(),
)
assert result["success"] is True
assert result["route"] == "scene_template"
assert [instruction for instruction, _ in control_calls] == [message]
assert not client.structured_calls and not client.legacy_calls
def test_local_first_callbacks_preserve_schedule_stop_route_and_answer():
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
events = []
result = assistant.stream(
"停止动态模式", conversation_id="conv-merged-schedule-stop", principal="test",
history=[], emit=events.append,
execute_control=lambda instruction, _progress: {
"request_id": "req-stop-merged", "utterance": instruction,
"status": "succeeded", "execution_mode": "dry_run",
"orchestration_route": "mode_schedule_stop",
"schedule_execution": {"status": "idle"},
},
preview_control=lambda *_args: pytest.fail("schedule stop must retain its scheduler route"),
supplement_control=lambda *_args: pytest.fail("schedule stop is not an unresolved control"),
control_terms=CONTROL_TERMS,
)
assert result["success"] is True
assert "已模拟停止动态模式" in result["answer"]
assert not client.structured_calls and not client.legacy_calls
def _structured_plan(
*,
temperature: float = 24,
shade_position: int = 100,
) -> dict[str, object]:
return {
"requests": [
{
"capability": "climate.set_temperature",
"target_scope": "vehicle",
"parameters": [{"name": "temperature_c", "value": temperature}],
},
{
"capability": "roof.set_shade_position",
"target_scope": "vehicle",
"parameters": [{"name": "position_pct", "value": shade_position}],
},
],
"ambiguities": [],
"confidence": 0.94,
}
def _legacy_plan(*, temperature: float = 24) -> dict[str, object]:
structured = _structured_plan(temperature=temperature)
requests = []
domains = {"climate.set_temperature": "climate", "roof.set_shade_position": "roof"}
for item in structured["requests"]:
requests.append(
{
"domain": domains[item["capability"]],
"capability": item["capability"],
"target_scope": item["target_scope"],
"operation": "set",
"duration_ms": None,
"parameters": item["parameters"],
"reason": "旧链路候选动作。",
}
)
return {
"detected_domains": ["climate", "roof"],
"requests": requests,
"ambiguities": [],
"decision_summary": ["旧链路生成候选计划。"],
"confidence": 0.94,
}
def _completed_turn(
thread_id: str,
turn_id: str,
answer: str,
) -> ActiveCodexTurn:
turn = ActiveCodexTurn(thread_id=thread_id, turn_id=turn_id, events=queue.Queue())
_finish_turn(turn, answer)
return turn
def _finish_turn(turn: ActiveCodexTurn, answer: str) -> None:
item_id = f"answer-{turn.turn_id}"
turn.events.put(
{
"method": "item/started",
"params": {
"item": {
"id": item_id,
"type": "agentMessage",
"text": "",
"phase": "final_answer",
}
},
}
)
turn.events.put(
{
"method": "item/agentMessage/delta",
"params": {"itemId": item_id, "delta": answer},
}
)
turn.events.put(
{
"method": "item/completed",
"params": {
"item": {
"id": item_id,
"type": "agentMessage",
"text": answer,
"phase": "final_answer",
}
},
}
)
turn.events.put(
{
"method": "turn/completed",
"params": {
"turn": {
"id": turn.turn_id,
"status": "completed",
"items": [],
"error": None,
}
},
}
)
class StructuredSceneClient:
def __init__(self) -> None:
self.structured_calls: list[dict[str, object]] = []
self.legacy_calls: list[dict[str, object]] = []
self.thread_instructions: list[str] = []
self.finished: list[ActiveCodexTurn] = []
self.interrupted: list[ActiveCodexTurn] = []
self.unsubscribed: list[str] = []
self.structured_answers: queue.Queue[str | BaseException] = queue.Queue()
self.on_structured_start: Callable[[], None] | None = None
self.structured_turn_factory: Callable[[str, str], ActiveCodexTurn] | None = None
self.on_legacy_start: Callable[[str, ActiveCodexTurn], None] | None = None
self._lock = threading.Lock()
@property
def available(self) -> bool:
return True
@property
def status(self) -> str:
return "ready"
def start(self, _callback_url: str, _callback_token: str) -> None:
return None
def close(self) -> None:
return None
def start_thread(
self,
*,
developer_instructions: str,
ephemeral: bool = True,
replace_developer_instructions: bool = False,
timeout: float | None = None,
) -> str:
assert ephemeral is True
del replace_developer_instructions, timeout
with self._lock:
self.thread_instructions.append(developer_instructions)
return f"thread-{len(self.thread_instructions)}"
def start_structured_turn(
self,
thread_id: str,
text: str,
*,
application_context: Mapping[str, object] | None = None,
output_schema: Mapping[str, object],
timeout: float | None = None,
) -> ActiveCodexTurn:
del timeout
with self._lock:
call_index = len(self.structured_calls) + 1
self.structured_calls.append(
{
"thread_id": thread_id,
"text": text,
"application_context": deepcopy(dict(application_context or {})),
"output_schema": deepcopy(dict(output_schema)),
}
)
if self.on_structured_start is not None:
self.on_structured_start()
turn_id = f"structured-{call_index}"
if self.structured_turn_factory is not None:
return self.structured_turn_factory(thread_id, turn_id)
try:
answer = self.structured_answers.get_nowait()
except queue.Empty:
answer = json.dumps(_structured_plan(), ensure_ascii=False)
if isinstance(answer, BaseException):
raise answer
return _completed_turn(thread_id, turn_id, answer)
def start_turn(
self,
thread_id: str,
text: str,
request_token: str,
*,
application_context: Mapping[str, object] | None = None,
) -> ActiveCodexTurn:
with self._lock:
call_index = len(self.legacy_calls) + 1
self.legacy_calls.append(
{
"thread_id": thread_id,
"text": text,
"request_token": request_token,
"application_context": deepcopy(dict(application_context or {})),
}
)
turn = _completed_turn(thread_id, f"legacy-{call_index}", "旧链路已生成模式。")
if self.on_legacy_start is not None:
self.on_legacy_start(request_token, turn)
return turn
def finish_turn(
self,
turn: ActiveCodexTurn,
timeout: float | None = None,
) -> None:
del timeout
self.finished.append(turn)
def interrupt(
self,
turn: ActiveCodexTurn,
timeout: float | None = None,
) -> None:
del timeout
self.interrupted.append(turn)
def unsubscribe_thread(
self,
thread_id: str,
timeout: float | None = None,
) -> None:
del timeout
self.unsubscribed.append(thread_id)
def _scene_context(
revision: str = "scene-contract-a",
*,
vehicle_id: str = "denza_n7",
) -> dict[str, object]:
return {
"schema_version": "n7web-scene-composition/v1",
"composition_revision": revision,
"vehicle": {"id": vehicle_id, "name": "腾势 N7"},
"capabilities": [
{
"id": "climate.set_temperature",
"domain": "climate",
"target_scopes": ["vehicle", "driver", "passenger"],
"parameters": [
{
"name": "temperature_c",
"type": "number",
"required": True,
"minimum": 16,
"maximum": 32,
}
],
},
{
"id": "roof.set_shade_position",
"domain": "roof",
"target_scopes": ["vehicle"],
"parameters": [
{
"name": "position_pct",
"type": "integer",
"required": True,
"minimum": 0,
"maximum": 100,
}
],
},
],
}
def _catalog(*, vehicle_id: str = "denza_n7") -> dict[str, object]:
return {
"catalog_revision": "full-runtime-revision",
"vehicle": {"id": vehicle_id, "name": "腾势 N7"},
"modes": [],
"source_status": {"modes": "ready"},
}
def _scene_template(
*,
template_id: str = "viewing",
name: str = "观影模式",
aliases: list[str] | None = None,
) -> dict[str, object]:
revision = f"revision-{template_id}"
plan = _legacy_plan()
plan["metadata"] = {
"source": "scene_template",
"template_id": template_id,
"template_revision": revision,
}
return {
"id": template_id,
"name": name,
"aliases": aliases or ["电影模式"],
"assistant_callable": True,
"template_revision": revision,
"plan": plan,
}
def _catalog_with_templates(
*templates: Mapping[str, object],
modes: list[dict[str, object]] | None = None,
) -> dict[str, object]:
catalog = _catalog()
catalog["modes"] = deepcopy(modes or [])
catalog["scene_templates"] = [deepcopy(dict(template)) for template in templates]
catalog["source_status"]["scene_templates"] = "ready"
return catalog
def _preview_result(
mode_name: str,
*,
operation_count: int = 2,
success: bool = True,
) -> dict[str, object]:
if not success:
return {
"request_id": "req-failed",
"status": "failed",
"execution_mode": "dry_run",
"hardware_execution_allowed": False,
"orchestration_route": "mode_profile_create_preview",
"validation": [{"code": "invalid_scene", "message": "invalid"}],
}
return {
"request_id": f"req-{mode_name}",
"status": "succeeded",
"execution_mode": "dry_run",
"execution_outcome": "simulated",
"hardware_execution_allowed": False,
"orchestration_route": "mode_profile_create_preview",
"validation": [],
"intent_ir": {"spec": {"actions": [{}, {}][:operation_count]}},
"mode_profile_draft": {
"name": mode_name,
"instruction": f"进入{mode_name}",
"source_request_id": f"req-{mode_name}",
"vehicle_id": "denza_n7",
"domains": ["climate", "roof"],
"operation_count": operation_count,
"generation_source": "codex_scene_composition",
},
}
def _invoke(
assistant: CodexAssistantService,
message: str,
executor: Callable[..., dict[str, object]],
*,
conversation_id: str,
principal: str = "alice",
scene_context: Mapping[str, object] | None = None,
catalog: Mapping[str, object] | None = None,
emit_handler: Callable[[dict[str, object]], bool | None] | None = None,
) -> tuple[dict[str, object], list[dict[str, object]]]:
events: list[dict[str, object]] = []
def emit(event: dict[str, object]) -> bool | None:
events.append(event)
return emit_handler(event) if emit_handler is not None else None
result = assistant.stream(
message,
conversation_id=conversation_id,
principal=principal,
history=[],
emit=emit,
execute_control=executor,
capability_snapshot=catalog or _catalog(),
capability_context={"general": "context"},
scene_capability_context=scene_context or _scene_context(),
control_terms=CONTROL_TERMS,
)
return result, events
def test_exact_scene_template_hit_skips_codex_and_previews_a_fresh_plan() -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
template = _scene_template()
observed: list[dict[str, object]] = []
def execute(
instruction: str,
_progress: Callable[[dict[str, object]], None],
assistant_plan: Mapping[str, object],
) -> dict[str, object]:
assert instruction == "构建一个观影模式"
observed.append(deepcopy(dict(assistant_plan)))
# A service callback must not be able to mutate the catalog-owned plan.
assistant_plan["requests"][0]["parameters"][0]["value"] = 31
return _preview_result("观影模式")
result, events = _invoke(
assistant,
"构建一个观影模式",
execute,
conversation_id="conv-scene-template-hit",
catalog=_catalog_with_templates(template),
)
assert result["success"] is True
assert result["route"] == "scene_template"
assert client.structured_calls == []
assert client.legacy_calls == []
assert len(observed) == 1
assert observed[0]["metadata"] == template["plan"]["metadata"]
assert template["plan"]["requests"][0]["parameters"][0]["value"] == 24
assert events[0]["engine"] == "n7web-scene-template"
def test_scene_template_miss_falls_through_to_structured_scene_composer() -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
observed: list[dict[str, object]] = []
def execute(
_instruction: str,
_progress: Callable[[dict[str, object]], None],
assistant_plan: Mapping[str, object],
) -> dict[str, object]:
observed.append(deepcopy(dict(assistant_plan)))
return _preview_result("星夜模式")
result, events = _invoke(
assistant,
"构建一个星夜模式",
execute,
conversation_id="conv-scene-template-miss",
catalog=_catalog_with_templates(_scene_template()),
)
assert result["success"] is True
assert len(client.structured_calls) == 1
assert client.legacy_calls == []
assert len(observed) == 1
assert "metadata" not in observed[0]
assert events[0]["engine"] == "codex-app-server-scene-composer"
def test_registered_mode_match_takes_precedence_over_same_named_template() -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
call_arity: list[int] = []
def execute(*args: object) -> dict[str, object]:
call_arity.append(len(args))
return _preview_result("观影模式")
result, events = _invoke(
assistant,
"构建一个观影模式",
execute,
conversation_id="conv-scene-template-registered-priority",
catalog=_catalog_with_templates(
_scene_template(),
modes=[
{
"id": "viewing-registered",
"name": "观影模式",
"aliases": ["电影模式"],
"assistant_callable": True,
}
],
),
)
assert result["success"] is True
assert call_arity == [2]
assert client.structured_calls == []
assert client.legacy_calls == []
assert events[0]["engine"] == "n7web-mode-builder"
def test_explicit_scene_settings_take_precedence_over_template_defaults() -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
instructions: list[str] = []
call_arity: list[int] = []
def execute(*args: object) -> dict[str, object]:
call_arity.append(len(args))
instructions.append(str(args[0]))
result = _preview_result("观影模式", operation_count=1)
result["mode_profile_draft"]["generation_source"] = "explicit_scene_requirements"
return result
result, events = _invoke(
assistant,
"构建一个观影模式,空调温度调整到25度",
execute,
conversation_id="conv-scene-template-explicit-priority",
catalog=_catalog_with_templates(_scene_template()),
)
assert result["success"] is True
assert instructions == ["构建一个观影模式,空调温度调整到25度"]
assert call_arity == [2]
assert client.structured_calls == []
assert client.legacy_calls == []
assert events[0]["engine"] == "n7web-mode-builder"
@pytest.mark.parametrize(
("message", "requested_name"),
(
("我想创建一个观影模式", "观影模式"),
("我希望构建观影模式呀!", "观影模式"),
("麻烦帮我新建一下观影模式吧", "观影模式"),
("请帮忙生成一套“观影模式”,先预览一下。", "观影模式"),
("可以帮我创建个「观影模式」给我看看", "观影模式"),
("能不能帮我创建一个影院模式,给我看看呀?", "影院模式"),
("能帮我创建一个观影模式吗?", "观影模式"),
("能否帮我创建一个影院模式吗", "影院模式"),
("可不可以帮我创建观影模式?", "观影模式"),
("请问能不能帮我创建影院模式吗?", "影院模式"),
("给我添加一个『电影模式』,预览看看!", "电影模式"),
("请帮我创建一个'影院模式', 给我看看!", "影院模式"),
("请 帮 我 创 建 一 个 《观 影 模 式》 吧 !", "观影模式"),
),
)
def test_oral_template_create_variants_keep_the_zero_codex_fast_path(
message: str,
requested_name: str,
) -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
template = _scene_template(aliases=["电影模式", "影院模式"])
observed: list[tuple[str, dict[str, object]]] = []
def execute(
instruction: str,
_progress: Callable[[dict[str, object]], None],
assistant_plan: Mapping[str, object],
) -> dict[str, object]:
observed.append((instruction, deepcopy(dict(assistant_plan))))
return _preview_result(requested_name)
result, events = _invoke(
assistant,
message,
execute,
conversation_id=f"conv-oral-template-{abs(hash(message))}",
catalog=_catalog_with_templates(template),
)
assert _mode_profile_create_parts(message) == (requested_name, "")
assert result["success"] is True
assert result["route"] == "scene_template"
assert events[0]["route"] == "scene_template"
assert events[0]["engine"] == "n7web-scene-template"
action = next(event for event in events if event["type"] == "action.completed")
assert action["payload"]["mode_profile_draft"]["name"] == requested_name
assert action["payload"]["execution_mode"] == "dry_run"
assert action["payload"]["hardware_execution_allowed"] is False
assert len(observed) == 1
assert observed[0][1]["metadata"] == template["plan"]["metadata"]
assert client.thread_instructions == []
assert client.structured_calls == []
assert client.legacy_calls == []
@pytest.mark.parametrize(
"message",
(
"构建一个观影模式并预览",
"请创建观影模式,先预览一下",
"我希望创建观影模式:让我先看一下方案",
"麻烦帮我生成观影模式,给我看看吧",
"能不能帮我创建影院模式并让我先看看呀?",
),
)
def test_preview_and_look_suffixes_are_not_misclassified_as_device_settings(
message: str,
) -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
template = _scene_template(aliases=["影院模式"])
executor_arity: list[int] = []
def execute(*args: object) -> dict[str, object]:
executor_arity.append(len(args))
return _preview_result("影院模式" if "影院" in message else "观影模式")
result, events = _invoke(
assistant,
message,
execute,
conversation_id=f"conv-preview-suffix-{abs(hash(message))}",
catalog=_catalog_with_templates(template),
)
parts = _mode_profile_create_parts(message)
assert parts is not None
assert parts[1] == ""
assert result["route"] == "scene_template"
assert executor_arity == [3]
assert events[0]["engine"] == "n7web-scene-template"
assert client.structured_calls == []
assert client.legacy_calls == []
@pytest.mark.parametrize(
("message", "expected_settings"),
(
("我想构建一个观影模式,空调温度调整到25度", "空调温度调整到25度"),
("请帮我创建一个影院模式:遮阳帘设置为100%", "遮阳帘设置为100%"),
(
"能不能帮我创建观影模式,把车窗全部关闭、氛围灯调暗",
"把车窗全部关闭、氛围灯调暗",
),
),
)
def test_oral_create_with_explicit_device_settings_never_uses_template_defaults(
message: str,
expected_settings: str,
) -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
executor_calls: list[tuple[object, ...]] = []
def execute(*args: object) -> dict[str, object]:
executor_calls.append(args)
result = _preview_result("观影模式", operation_count=1)
result["mode_profile_draft"]["generation_source"] = (
"explicit_scene_requirements"
)
return result
result, events = _invoke(
assistant,
message,
execute,
conversation_id=f"conv-explicit-settings-{abs(hash(message))}",
catalog=_catalog_with_templates(
_scene_template(aliases=["影院模式"]),
),
)
parts = _mode_profile_create_parts(message)
assert parts is not None
assert parts[1] == expected_settings
assert result["success"] is True
assert events[0]["route"] == "vehicle_control"
assert events[0]["engine"] == "n7web-mode-builder"
assert len(executor_calls) == 1
assert len(executor_calls[0]) == 2
assert executor_calls[0][0] == " ".join(message.strip().split())
assert client.structured_calls == []
assert client.legacy_calls == []
@pytest.mark.parametrize(
"message",
(
"我想创建一个星空漫游模式",
"麻烦帮我构建星空漫游模式吧",
"能不能帮我创建一个星空漫游模式,先给我看看呀?",
),
)
def test_unknown_oral_scene_names_still_fall_through_to_scene_composer(
message: str,
) -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
executor_arity: list[int] = []
def execute(*args: object) -> dict[str, object]:
executor_arity.append(len(args))
return _preview_result("星空漫游模式")
result, events = _invoke(
assistant,
message,
execute,
conversation_id=f"conv-unknown-oral-scene-{abs(hash(message))}",
catalog=_catalog_with_templates(_scene_template()),
)
parts = _mode_profile_create_parts(message)
assert parts is not None
assert parts[1] == ""
assert result["success"] is True
assert events[0]["route"] == "scene_composer"
assert events[0]["engine"] == "codex-app-server-scene-composer"
assert len(client.structured_calls) == 1
assert client.legacy_calls == []
assert executor_arity == [3]
@pytest.mark.parametrize(
"message",
(
"不要创建观影模式",
"请别执行创建观影模式",
"先不要构建观影模式,给我解释一下",
"请解释一下“创建一个观影模式”是什么意思",
"引用‘构建一个观影模式’,不要执行",
"复述:请创建一个观影模式",
"如何创建一个观影模式?",
"是否支持创建观影模式?",
"能否创建观影模式?",
"你可以创建哪些模式?",
"构建一个观影模式,空调温度是25度还是26度?",
"构建一个模式",
"创建一个功能模式",
"添加一个新模式",
"预览观影模式",
),
)
def test_negative_quoted_explanatory_and_capability_queries_never_execute(
message: str,
) -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
executor_calls = 0
def execute(*_args: object) -> dict[str, object]:
nonlocal executor_calls
executor_calls += 1
return _preview_result("观影模式")
result, events = _invoke(
assistant,
message,
execute,
conversation_id=f"conv-safe-scene-language-{abs(hash(message))}",
catalog=_catalog_with_templates(_scene_template()),
)
assert _mode_profile_create_parts(message) is None
assert result["route"] == "agent"
assert events[0]["route"] == "agent"
assert executor_calls == 0
assert client.structured_calls == []
assert len(client.legacy_calls) == 1
def test_unknown_mode_uses_one_structured_turn_then_local_dry_run() -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
observed: list[tuple[str, dict[str, object]]] = []
def execute(
instruction: str,
_progress: Callable[[dict[str, object]], None],
assistant_plan: Mapping[str, object],
) -> dict[str, object]:
observed.append((instruction, deepcopy(dict(assistant_plan))))
return _preview_result("星夜模式")
result, events = _invoke(
assistant,
"构建一个星夜模式",
execute,
conversation_id="conv-scene-fast-success",
)
assert len(client.structured_calls) == 1
assert client.legacy_calls == []
assert observed[0][0] == "构建一个星夜模式"
assert [item["capability"] for item in observed[0][1]["requests"]] == [
"climate.set_temperature",
"roof.set_shade_position",
]
call = client.structured_calls[0]
expected_context = _scene_context()
expected_context["seat_scope_policy"] = {
"selected_scopes": ["passenger"],
"default_scope": "passenger",
"applies_to": "seat capabilities in every phase",
}
expected_context["natural_language_routing"] = {
"original_utterance": "构建一个星夜模式",
"parsed_clauses": [],
"resolved_clauses": [],
"unresolved_clauses": ["构建一个星夜模式"],
"cloud_input_utterance": "构建一个星夜模式",
}
assert call["application_context"] == expected_context
assert call["output_schema"]["type"] == "object"
assert call["output_schema"]["additionalProperties"] is False
assert "requests" in call["output_schema"]["required"]
assert result["success"] is True
assert "预览" in result["answer"]
assert "2项设备动作" in result["answer"]
assert any(event["type"] == "action.completed" for event in events)
assert all("真实下发" not in str(event) for event in events)
@pytest.mark.parametrize(
"bad_answer",
(
"不是 JSON",
"{}",
'{"requests":"not-a-list"}',
),
)
def test_malformed_structured_output_falls_back_to_existing_agent_path(
bad_answer: str,
) -> None:
client = StructuredSceneClient()
client.structured_answers.put(bad_answer)
assistant = CodexAssistantService(client)
fallback_plan = _legacy_plan(temperature=23)
calls: list[dict[str, object]] = []
def execute(
_instruction: str,
_progress: Callable[[dict[str, object]], None],
assistant_plan: Mapping[str, object],
) -> dict[str, object]:
calls.append(deepcopy(dict(assistant_plan)))
return _preview_result("阅读模式")
def legacy(request_token: str, _turn: ActiveCodexTurn) -> None:
assistant.execute_cockpit_request(request_token, fallback_plan)
client.on_legacy_start = legacy
result, _events = _invoke(
assistant,
"构建一个阅读模式",
execute,
conversation_id=f"conv-scene-fallback-{abs(hash(bad_answer))}",
)
assert len(client.structured_calls) == 1
assert len(client.legacy_calls) == 1
assert len(calls) == 1
assert [item["capability"] for item in calls[0]["requests"]] == [
"climate.set_temperature",
"roof.set_shade_position",
]
assert calls[0]["requests"][0]["parameters"] == [{"name": "temperature_c", "value": 23}]
assert result["route"] == "agent"
assert "预览" in result["answer"]
def test_same_normalized_scene_and_revision_reuses_plan_but_revalidates_every_request() -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
observed: list[dict[str, object]] = []
def execute(
_instruction: str,
_progress: Callable[[dict[str, object]], None],
assistant_plan: Mapping[str, object],
) -> dict[str, object]:
observed.append(deepcopy(dict(assistant_plan)))
return _preview_result("静心模式")
first, _ = _invoke(
assistant,
"创建一个静心模式",
execute,
conversation_id="conv-scene-cache-first",
)
second, _ = _invoke(
assistant,
"构建一个静心模式",
execute,
conversation_id="conv-scene-cache-second",
)
assert first["success"] is second["success"] is True
assert len(client.structured_calls) == 1
assert len(observed) == 2
assert observed[0] == observed[1]
@pytest.mark.parametrize("changed_dimension", ("revision", "vehicle"))
def test_cache_is_invalidated_when_scene_contract_or_vehicle_changes(
changed_dimension: str,
) -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
def execute(
_instruction: str,
_progress: Callable[[dict[str, object]], None],
_assistant_plan: Mapping[str, object],
) -> dict[str, object]:
return _preview_result("接待模式")
_invoke(
assistant,
"构建一个接待模式",
execute,
conversation_id="conv-scene-invalidate-first",
)
context = (
_scene_context("scene-contract-b")
if changed_dimension == "revision"
else _scene_context(vehicle_id="another_vehicle")
)
catalog = _catalog(
vehicle_id="another_vehicle" if changed_dimension == "vehicle" else "denza_n7"
)
_invoke(
assistant,
"构建一个接待模式",
execute,
conversation_id="conv-scene-invalidate-second",
scene_context=context,
catalog=catalog,
)
assert len(client.structured_calls) == 2
def test_failed_local_validation_is_never_cached() -> None:
client = StructuredSceneClient()
client.structured_answers.put(json.dumps(_structured_plan(temperature=18), ensure_ascii=False))
client.structured_answers.put(json.dumps(_structured_plan(temperature=25), ensure_ascii=False))
assistant = CodexAssistantService(client)
attempts = 0
def execute(
_instruction: str,
_progress: Callable[[dict[str, object]], None],
_assistant_plan: Mapping[str, object],
) -> dict[str, object]:
nonlocal attempts
attempts += 1
return _preview_result("派对模式", success=attempts > 1)
first, _ = _invoke(
assistant,
"构建一个派对模式",
execute,
conversation_id="conv-scene-invalid-first",
)
second, _ = _invoke(
assistant,
"构建一个派对模式",
execute,
conversation_id="conv-scene-invalid-second",
)
assert first["success"] is False
assert second["success"] is True
assert len(client.structured_calls) == 2
def test_concurrent_identical_cold_requests_share_one_planner_turn() -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
planner_entered = threading.Event()
release_planner = threading.Event()
executor_calls = 0
executor_lock = threading.Lock()
def hold_planner() -> None:
planner_entered.set()
assert release_planner.wait(timeout=3)
client.on_structured_start = hold_planner
def execute(
_instruction: str,
_progress: Callable[[dict[str, object]], None],
_assistant_plan: Mapping[str, object],
) -> dict[str, object]:
nonlocal executor_calls
with executor_lock:
executor_calls += 1
return _preview_result("露营模式")
def run(index: int) -> dict[str, object]:
result, _ = _invoke(
assistant,
"构建一个露营模式",
execute,
conversation_id=f"conv-scene-singleflight-{index}",
)
return result
with ThreadPoolExecutor(max_workers=2) as pool:
first = pool.submit(run, 1)
assert planner_entered.wait(timeout=2)
second = pool.submit(run, 2)
time.sleep(0.15)
assert len(client.structured_calls) == 1
release_planner.set()
results = [first.result(timeout=3), second.result(timeout=3)]
assert all(result["success"] is True for result in results)
assert len(client.structured_calls) == 1
# A plan cache never authorizes execution: both requests still traverse the
# current local validation/dry-run callback independently.
assert executor_calls == 2
def test_cached_plan_is_copied_before_each_validation() -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
seen_temperatures: list[float] = []
def execute(
_instruction: str,
_progress: Callable[[dict[str, object]], None],
assistant_plan: Mapping[str, object],
) -> dict[str, object]:
requests = assistant_plan["requests"]
assert isinstance(requests, list)
temperature = requests[0]["parameters"][0]["value"]
seen_temperatures.append(temperature)
requests[0]["parameters"][0]["value"] = 31
return _preview_result("专注模式")
for suffix in ("first", "second"):
_invoke(
assistant,
"构建一个专注模式",
execute,
conversation_id=f"conv-scene-copy-{suffix}",
)
assert len(client.structured_calls) == 1
assert seen_temperatures == [24, 24]
def test_scene_preview_never_reports_or_requests_hardware_execution() -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
calls = 0
def execute(
instruction: str,
_progress: Callable[[dict[str, object]], None],
assistant_plan: Mapping[str, object],
) -> dict[str, object]:
nonlocal calls
calls += 1
assert instruction == "构建一个观景模式"
assert assistant_plan["requests"]
return _preview_result("观景模式")
result, events = _invoke(
assistant,
"构建一个观景模式",
execute,
conversation_id="conv-scene-no-hardware",
)
assert calls == 1
assert result["success"] is True
action_completed = next(event for event in events if event["type"] == "action.completed")
payload = action_completed["payload"]
assert payload["execution_mode"] == "dry_run"
assert payload["hardware_execution_allowed"] is False
assert "approval_token" not in json.dumps(events, ensure_ascii=False)
assert "command_plans" not in json.dumps(events, ensure_ascii=False)
def test_validated_scene_plan_cache_is_shared_across_principals() -> None:
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
executor_calls = 0
def execute(
_instruction: str,
_progress: Callable[[dict[str, object]], None],
_assistant_plan: Mapping[str, object],
) -> dict[str, object]:
nonlocal executor_calls
executor_calls += 1
return _preview_result("露营模式")
first, _ = _invoke(
assistant,
"构建一个露营模式",
execute,
conversation_id="conv-scene-global-cache-a",
principal="alice",
)
second, _ = _invoke(
assistant,
"创建一个露营模式",
execute,
conversation_id="conv-scene-global-cache-b",
principal="bob",
)
assert first["success"] is second["success"] is True
assert len(client.structured_calls) == 1
# Cross-user reuse applies only to the context-bound candidate plan. Each
# user's request still enters the current local dry-run validation chain.
assert executor_calls == 2
def test_structured_planner_timeout_returns_explicit_failure_without_general_fallback() -> None:
client = StructuredSceneClient()
hanging_turns: list[ActiveCodexTurn] = []
def hanging_turn(thread_id: str, turn_id: str) -> ActiveCodexTurn:
turn = ActiveCodexTurn(thread_id=thread_id, turn_id=turn_id, events=queue.Queue())
hanging_turns.append(turn)
return turn
client.structured_turn_factory = hanging_turn
assistant = CodexAssistantService(client)
assistant._scene_turn_timeout = 0.05
executor_calls = 0
def execute(*_args: object) -> dict[str, object]:
nonlocal executor_calls
executor_calls += 1
return _preview_result("超时模式")
result, events = _invoke(
assistant,
"构建一个超时模式",
execute,
conversation_id="conv-scene-planner-timeout",
)
assert len(hanging_turns) == 1
assert client.interrupted == hanging_turns
assert client.legacy_calls == []
assert executor_calls == 0
assert result["route"] == "scene_composer"
assert result["success"] is False
assert "超过" in result["answer"]
assert any(event["type"] == "work.completed" and event["success"] is False for event in events)
assert any(
event["type"] == "answer.completed"
and event["route"] == "scene_composer"
and "超过" in event["answer"]
for event in events
)
assert any("超时" in str(event.get("display_text") or "") for event in events)
assert all("切换完整理解链路" not in str(event) for event in events)
def test_scene_planner_concurrency_limit_rejects_excess_cold_scene_without_queueing(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("CODEX_ASSISTANT_SCENE_MAX_CONCURRENT_PLANS", "1")
client = StructuredSceneClient()
assistant = CodexAssistantService(client)
first_planner_entered = threading.Event()
release_planners = threading.Event()
callback_lock = threading.Lock()
active_planners = 0
max_active_planners = 0
def hold_planner() -> None:
nonlocal active_planners, max_active_planners
with callback_lock:
active_planners += 1
max_active_planners = max(max_active_planners, active_planners)
first_planner_entered.set()
try:
assert release_planners.wait(timeout=3)
finally:
with callback_lock:
active_planners -= 1
client.on_structured_start = hold_planner
def execute(
_instruction: str,
_progress: Callable[[dict[str, object]], None],
_assistant_plan: Mapping[str, object],
) -> dict[str, object]:
return _preview_result("并发模式")
def run(index: int, mode_name: str) -> dict[str, object]:
result, _ = _invoke(
assistant,
f"构建一个{mode_name}",
execute,
conversation_id=f"conv-scene-concurrency-{index}",
principal=f"user-{index}",
)
return result
with ThreadPoolExecutor(max_workers=1) as pool:
first = pool.submit(run, 1, "森林模式")
assert first_planner_entered.wait(timeout=2)
second_result, second_events = _invoke(
assistant,
"构建一个阅读模式",
execute,
conversation_id="conv-scene-concurrency-2",
principal="user-2",
)
calls_before_release = len(client.structured_calls)
max_active_before_release = max_active_planners
release_planners.set()
first_result = first.result(timeout=3)
assert first_result["success"] is True
assert second_result["route"] == "scene_composer"
assert second_result["success"] is False
assert "任务较多" in second_result["answer"]
assert any(
event["type"] == "work.completed" and event["success"] is False for event in second_events
)
assert calls_before_release == 1
assert max_active_before_release == 1
assert len(client.structured_calls) == 1
assert client.legacy_calls == []
assert max_active_planners == 1
def test_singleflight_wait_timeout_fails_without_starting_a_second_agent_turn() -> None:
client = StructuredSceneClient()
active_ready = threading.Event()
active_turns: list[ActiveCodexTurn] = []
def hanging_turn(thread_id: str, turn_id: str) -> ActiveCodexTurn:
turn = ActiveCodexTurn(thread_id=thread_id, turn_id=turn_id, events=queue.Queue())
active_turns.append(turn)
active_ready.set()
return turn
client.structured_turn_factory = hanging_turn
assistant = CodexAssistantService(client)
assistant._scene_turn_timeout = 2
executor_calls = 0
def execute(
_instruction: str,
_progress: Callable[[dict[str, object]], None],
_assistant_plan: Mapping[str, object],
) -> dict[str, object]:
nonlocal executor_calls
executor_calls += 1
return _preview_result("亲子模式")
def run_leader() -> dict[str, object]:
result, _ = _invoke(
assistant,
"构建一个亲子模式",
execute,
conversation_id="conv-scene-wait-leader",
principal="leader",
)
return result
with ThreadPoolExecutor(max_workers=1) as pool:
leader = pool.submit(run_leader)
assert active_ready.wait(timeout=2)
assistant._scene_turn_timeout = 0.05
waiter_result, waiter_events = _invoke(
assistant,
"创建一个亲子模式",
execute,
conversation_id="conv-scene-wait-timeout",
principal="waiter",
)
structured_calls_before_completion = len(client.structured_calls)
legacy_calls_before_completion = list(client.legacy_calls)
executor_calls_before_completion = executor_calls
assistant._scene_turn_timeout = 2
_finish_turn(
active_turns[0],
json.dumps(_structured_plan(), ensure_ascii=False),
)
leader_result = leader.result(timeout=3)
assert structured_calls_before_completion == 1
assert legacy_calls_before_completion == []
assert executor_calls_before_completion == 0
assert waiter_result["route"] == "scene_composer"
assert waiter_result["success"] is False
assert "超过" in waiter_result["answer"]
assert any(
event["type"] == "work.completed" and event["success"] is False for event in waiter_events
)
assert any("超时" in str(event.get("display_text") or "") for event in waiter_events)
assert leader_result["success"] is True
assert executor_calls == 1
assert client.interrupted == []
def test_cancelled_singleflight_waiter_does_not_cancel_or_execute_leader_plan() -> None:
client = StructuredSceneClient()
active_ready = threading.Event()
active_turns: list[ActiveCodexTurn] = []
def hanging_turn(thread_id: str, turn_id: str) -> ActiveCodexTurn:
turn = ActiveCodexTurn(thread_id=thread_id, turn_id=turn_id, events=queue.Queue())
active_turns.append(turn)
active_ready.set()
return turn
client.structured_turn_factory = hanging_turn
assistant = CodexAssistantService(client)
assistant._scene_turn_timeout = 2
executor_calls = 0
def execute(
_instruction: str,
_progress: Callable[[dict[str, object]], None],
_assistant_plan: Mapping[str, object],
) -> dict[str, object]:
nonlocal executor_calls
executor_calls += 1
return _preview_result("陪伴模式")
def run_leader() -> dict[str, object]:
result, _ = _invoke(
assistant,
"构建一个陪伴模式",
execute,
conversation_id="conv-scene-cancel-leader",
principal="leader",
)
return result
def cancel_on_singleflight_wait(event: dict[str, object]) -> bool | None:
if event.get("type") == "work.progress" and "相同场景" in str(
event.get("display_text") or ""
):
return False
return None
with ThreadPoolExecutor(max_workers=1) as pool:
leader = pool.submit(run_leader)
assert active_ready.wait(timeout=2)
waiter_result, _ = _invoke(
assistant,
"创建一个陪伴模式",
execute,
conversation_id="conv-scene-cancel-waiter",
principal="waiter",
emit_handler=cancel_on_singleflight_wait,
)
assert waiter_result == {"cancelled": True}
assert len(client.structured_calls) == 1
assert client.legacy_calls == []
assert executor_calls == 0
assert client.interrupted == []
_finish_turn(
active_turns[0],
json.dumps(_structured_plan(), ensure_ascii=False),
)
leader_result = leader.result(timeout=3)
assert leader_result["success"] is True
assert executor_calls == 1
assert client.interrupted == []
def test_continuous_delta_stream_still_detects_browser_cancellation() -> None:
client = StructuredSceneClient()
active_turns: list[ActiveCodexTurn] = []
def busy_turn(thread_id: str, turn_id: str) -> ActiveCodexTurn:
turn = ActiveCodexTurn(thread_id=thread_id, turn_id=turn_id, events=queue.Queue())
for _ in range(10_000):
turn.events.put(
{
"method": "item/agentMessage/delta",
"params": {"delta": "x"},
}
)
active_turns.append(turn)
return turn
client.structured_turn_factory = busy_turn
assistant = CodexAssistantService(client)
assistant._scene_progress_interval = 0.001
executor_calls = 0
def execute(*_args: object) -> dict[str, object]:
nonlocal executor_calls
executor_calls += 1
return _preview_result("持续输出模式")
def disconnect_on_heartbeat(event: dict[str, object]) -> bool | None:
if event.get("type") == "work.progress" and event.get("display_text") == (
"小迪正在生成结构化模式方案……"
):
return False
return None
result, _events = _invoke(
assistant,
"构建一个持续输出模式",
execute,
conversation_id="conv-scene-continuous-cancel",
emit_handler=disconnect_on_heartbeat,
)
assert result == {"cancelled": True}
assert client.interrupted == active_turns
assert active_turns[0].events.qsize() > 0
assert client.legacy_calls == []
assert executor_calls == 0
def test_cancelled_singleflight_leader_allows_a_follower_to_replan() -> None:
client = StructuredSceneClient()
first_planner_entered = threading.Event()
follower_waiting = threading.Event()
release_first_planner = threading.Event()
starts = 0
starts_lock = threading.Lock()
executor_calls = 0
def hold_only_first_planner() -> None:
nonlocal starts
with starts_lock:
starts += 1
current = starts
if current == 1:
first_planner_entered.set()
assert release_first_planner.wait(timeout=3)
client.on_structured_start = hold_only_first_planner
assistant = CodexAssistantService(client)
def execute(
_instruction: str,
_progress: Callable[[dict[str, object]], None],
_assistant_plan: Mapping[str, object],
) -> dict[str, object]:
nonlocal executor_calls
executor_calls += 1
return _preview_result("接续模式")
def cancel_leader(event: dict[str, object]) -> bool | None:
if event.get("type") == "work.progress" and "小迪已开始" in str(
event.get("display_text") or ""
):
return False
return None
def observe_waiter(event: dict[str, object]) -> bool | None:
if event.get("type") == "work.progress" and "相同场景" in str(
event.get("display_text") or ""
):
follower_waiting.set()
return None
with ThreadPoolExecutor(max_workers=2) as pool:
leader = pool.submit(
_invoke,
assistant,
"构建一个接续模式",
execute,
conversation_id="conv-scene-replan-leader",
principal="leader",
emit_handler=cancel_leader,
)
assert first_planner_entered.wait(timeout=2)
follower = pool.submit(
_invoke,
assistant,
"创建一个接续模式",
execute,
conversation_id="conv-scene-replan-follower",
principal="follower",
emit_handler=observe_waiter,
)
assert follower_waiting.wait(timeout=2)
release_first_planner.set()
leader_result, _leader_events = leader.result(timeout=3)
follower_result, _follower_events = follower.result(timeout=3)
assert leader_result == {"cancelled": True}
assert follower_result["success"] is True
assert len(client.structured_calls) == 2
assert client.legacy_calls == []
assert executor_calls == 1