from __future__ import annotations import asyncio from pathlib import Path from server.agent_core.intent import parse_fast from server.aps_domain.workflow import handle_intent from server.contracts import IntentResult from server.state.packs import load_pack, resolve_pack_reference from server.state.store import WorldStore PACK_PATH = Path(__file__).resolve().parents[2] / "server" / "data" / "packs" / "optimize-simulation-v1.json" def test_chat_command_parses_data_pack_and_algorithm_slots(): world = load_pack(str(PACK_PATH)) result = parse_fast( "使用 Optimize synthetic debug V1 数据用 EDD 算法生成排产方案", world, ) assert result is not None assert result.intent == "flex.schedule" assert result.params["dataPackRef"] == "Optimize synthetic debug V1" assert result.params["engine"] == "OPTIMIZE" assert result.params["sortMode"] == "EDD" def test_pack_reference_resolves_registered_aliases(): pack = resolve_pack_reference("Optimize 模拟数据") assert pack is not None assert pack["file"] == "optimize-simulation-v1.json" def test_chat_command_parses_directory_file_and_algorithm_slots(): result = parse_fast( r"使用 D:\aps-data 目录下的 orders.xlsx 数据用 EDD 算法生成排产方案", {}, ) assert result is not None assert result.intent == "flex.schedule" assert result.params["dataDir"] == r"D:\aps-data" assert result.params["dataFile"] == "orders.xlsx" assert result.params["dataPath"].endswith(r"aps-data\orders.xlsx") assert result.params["sortMode"] == "EDD" assert result.params["engine"] == "OPTIMIZE" def test_chat_command_parses_directory_json_pack_and_algorithm_slots(): result = parse_fast( r"使用 D:\aps-data 目录下的 optimize-simulation-v1.json 数据用 EDD 算法生成排产方案", {}, ) assert result is not None assert result.intent == "flex.schedule" assert result.params["dataDir"] == r"D:\aps-data" assert result.params["dataFile"] == "optimize-simulation-v1.json" assert result.params["dataPath"].endswith(r"aps-data\optimize-simulation-v1.json") assert result.params["sortMode"] == "EDD" assert result.params["engine"] == "OPTIMIZE" def test_chat_command_loads_pack_and_materializes_optimize_result(tmp_path, monkeypatch): monkeypatch.setenv("APS_DB_DISABLED", "1") store = WorldStore(path=str(tmp_path / "world.json")) intent = parse_fast( "使用 Optimize synthetic debug V1 数据用 EDD 算法生成排产方案", store.data, ) assert intent is not None reply = asyncio.run(handle_intent(store, "round88", intent, actor="test")) assert "Optimize" in reply.text assert "Optimize synthetic debug V1" in reply.text block = next(block for block in reply.blocks if block.type == "flex-schedule") assert block.props["dataPack"]["file"] == "optimize-simulation-v1.json" assert block.props["algorithm"]["rule"] == "EDD" assert block.props["stats"]["vlCount"] == 10 assert block.props["stats"]["woCount"] == 72 assert store.data["flexScheduleVersions"][-1]["engineType"] == "OPTIMIZE" assert store.data["flexScheduleVersions"][-1]["algorithmId"] == "optimize.edd" def test_explicit_json_pack_path_materializes_optimize_result(tmp_path, monkeypatch): monkeypatch.setenv("APS_DB_DISABLED", "1") store = WorldStore(path=str(tmp_path / "world.json")) intent = IntentResult( intent="flex.schedule", params={ "dataDir": str(PACK_PATH.parent), "dataFile": PACK_PATH.name, "dataPath": str(PACK_PATH), "engine": "OPTIMIZE", "sortMode": "EDD", }, confidence=0.95, source="RULE_FAST", ) reply = asyncio.run(handle_intent(store, "round88-json", intent, actor="test")) block = next(block for block in reply.blocks if block.type == "flex-schedule") assert block.props["dataPack"]["file"] == PACK_PATH.name assert block.props["dataSource"]["file"] == PACK_PATH.name assert block.props["dataSource"]["paths"] == [str(PACK_PATH.resolve())] assert block.props["algorithm"]["rule"] == "EDD" assert block.props["stats"]["vlCount"] == 10 assert block.props["stats"]["woCount"] == 72 def test_empty_explicit_directory_does_not_reuse_current_world(tmp_path, monkeypatch): monkeypatch.setenv("APS_DB_DISABLED", "1") store = WorldStore(path=str(tmp_path / "world.json")) store.data = load_pack(str(PACK_PATH)) store._reset_counters() before_versions = len(store.data.get("flexScheduleVersions") or []) empty_dir = tmp_path / "empty-data" empty_dir.mkdir() intent = IntentResult( intent="flex.schedule", params={"dataDir": str(empty_dir), "engine": "OPTIMIZE", "sortMode": "EDD"}, confidence=0.95, source="RULE_FAST", ) reply = asyncio.run(handle_intent(store, "round88-empty", intent, actor="test")) assert "没有找到可读取的排产数据文件" in reply.text assert len(store.data.get("flexScheduleVersions") or []) == before_versions def test_unknown_pack_fails_closed_without_creating_schedule(tmp_path, monkeypatch): monkeypatch.setenv("APS_DB_DISABLED", "1") store = WorldStore(path=str(tmp_path / "world.json")) intent = parse_fast("使用不存在的数据,用 EDD 算法生成排产方案", store.data) assert intent is not None reply = asyncio.run(handle_intent(store, "round88", intent, actor="test")) assert "找不到数据包" in reply.text assert not store.data.get("flexScheduleVersions") def test_unreadable_directory_fails_closed_without_scheduling(tmp_path, monkeypatch): monkeypatch.setenv("APS_DB_DISABLED", "1") store = WorldStore(path=str(tmp_path / "world.json")) intent = parse_fast( r"使用 D:\missing-aps-data 目录下的 orders.xlsx 数据用 EDD 算法生成排产方案", store.data, ) assert intent is not None reply = asyncio.run(handle_intent(store, "round88", intent, actor="test")) assert "数据文件不存在" in reply.text or "数据目录不存在" in reply.text assert not store.data.get("flexScheduleVersions")