from __future__ import annotations import json import sys from pathlib import Path from cognitive_agent.application.scene_composer import ( SCENE_COMPOSER_INSTRUCTIONS, build_scene_output_schema, ) from cognitive_agent.infrastructure.codex.app_server import CodexAppServerClient ROOT = Path(__file__).resolve().parents[2] FAKE_SERVER = ROOT / "tests" / "fixtures" / "fake_codex_app_server.py" MCP_SERVER = ROOT / "src/cognitive_agent/infrastructure/codex/vehicle_mcp_server.py" CALLBACK_URL = "http://127.0.0.1:8765/api/internal/codex/vehicle-control" CALLBACK_TOKEN = "test-internal-token-123456" def _context() -> dict[str, object]: return { "schema_version": "n7web-scene-capabilities/v1", "planner_contract": "stable-absolute-set-actions-only", "composition_revision": "composition-test-a", "vehicle": {"id": "denza_n7", "name": "腾势 N7"}, "capabilities": [ { "id": "climate.set_temperature", "domain": "climate", "target_scopes": ["vehicle", "driver", "passenger"], "parameters": [ { "name": "temperature_c", "type": "number", "minimum": 16, "maximum": 32, "required": True, } ], } ], } def test_scene_planner_uses_replaced_instructions_and_app_server_output_schema( tmp_path: Path, ) -> None: context = _context() output_schema = build_scene_output_schema(context) client = CodexAppServerClient( cwd=tmp_path, codex_command=[sys.executable, "-u", str(FAKE_SERVER)], model="gpt-test-fast", reasoning_effort="low", request_timeout=2, startup_timeout=2, environment={"OPENAI_BASE_URL": "https://api.openai.com/v1"}, mcp_server_path=MCP_SERVER, ) try: client.start(CALLBACK_URL, CALLBACK_TOKEN) thread_id = client.start_thread( developer_instructions=SCENE_COMPOSER_INSTRUCTIONS, ephemeral=True, replace_developer_instructions=True, ) turn = client.start_structured_turn( thread_id, "构建一个专注模式", application_context=context, output_schema=output_schema, ) client.finish_turn(turn, timeout=2) finally: client.close() wire = [ json.loads(line) for line in (tmp_path / "wire.jsonl").read_text(encoding="utf-8").splitlines() ] thread_request = next(item for item in wire if item.get("method") == "thread/start") instructions = thread_request["params"]["developerInstructions"] assert instructions == SCENE_COMPOSER_INSTRUCTIONS.strip() assert "n7_vehicle.execute_cockpit_request" not in instructions assert "request_token" not in instructions turn_request = next(item for item in wire if item.get("method") == "turn/start") params = turn_request["params"] model_input = params["input"][0]["text"] assert params["outputSchema"] == output_schema assert params["effort"] == "low" assert params["approvalPolicy"] == "never" assert params["sandboxPolicy"] == {"type": "readOnly", "networkAccess": False} assert "N7WEB_SCENE_CAPABILITY_CONTEXT" in model_input assert '"composition_revision":"composition-test-a"' in model_input assert "构建一个专注模式" in model_input assert "request_token" not in model_input assert CALLBACK_TOKEN not in model_input