import os import sys PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if PROJECT_ROOT not in sys.path: sys.path.insert(0, PROJECT_ROOT) from web_interface.artifacts import extract_latest_artifacts def test_extract_latest_artifacts_prefers_tagged_files(tmp_path): workspace_dir = tmp_path / "workspace" / "demo_part" workspace_dir.mkdir(parents=True) code_path = workspace_dir / "model.py" model_path = workspace_dir / "part.stl" code_path.write_text("print('demo')\n", encoding="utf-8") model_path.write_text("solid demo\nendsolid demo\n", encoding="utf-8") messages = [ { "role": "assistant", "content": ( "Saved files\n" "<|code_file|>workspace/demo_part/model.py\n" "<|output_file|>workspace/demo_part/part.stl" ), } ] artifacts = extract_latest_artifacts(messages, project_root=tmp_path) assert artifacts["code_path"] == code_path.resolve(strict=False) assert artifacts["code_paths"] == [code_path.resolve(strict=False)] assert artifacts["model_path"] == model_path.resolve(strict=False) assert artifacts["model_paths"] == [model_path.resolve(strict=False)] assert artifacts["output_paths"] == [model_path.resolve(strict=False)] def test_extract_latest_artifacts_accepts_legacy_closing_tags(tmp_path): workspace_dir = tmp_path / "workspace" / "demo_part" workspace_dir.mkdir(parents=True) code_path = workspace_dir / "model.py" model_path = workspace_dir / "part.stl" code_path.write_text("print('demo')\n", encoding="utf-8") model_path.write_text("solid demo\nendsolid demo\n", encoding="utf-8") messages = [ { "role": "assistant", "content": ( "Saved files\n" "<|code_file|>./demo_part/model.py\n" "<|output_file|>./demo_part/part.stl" ), } ] artifacts = extract_latest_artifacts(messages, project_root=tmp_path / "workspace") assert artifacts["code_path"] == code_path.resolve(strict=False) assert artifacts["code_paths"] == [code_path.resolve(strict=False)] assert artifacts["model_path"] == model_path.resolve(strict=False) assert artifacts["model_paths"] == [model_path.resolve(strict=False)] assert artifacts["output_paths"] == [model_path.resolve(strict=False)] def test_extract_latest_artifacts_falls_back_to_latest_stl_near_model_py(tmp_path): workspace_dir = tmp_path / "workspace" / "fallback_case" workspace_dir.mkdir(parents=True) code_path = workspace_dir / "model.py" older_stl = workspace_dir / "older.stl" newer_stl = workspace_dir / "newer.stl" code_path.write_text("print('demo')\n", encoding="utf-8") older_stl.write_text("solid older\nendsolid older\n", encoding="utf-8") newer_stl.write_text("solid newer\nendsolid newer\n", encoding="utf-8") os.utime(older_stl, (1, 1)) os.utime(newer_stl, (2, 2)) messages = [ { "role": "assistant", "content": "<|code_file|>workspace/fallback_case/model.py", } ] artifacts = extract_latest_artifacts(messages, project_root=tmp_path) assert artifacts["code_path"] == code_path.resolve(strict=False) assert artifacts["code_paths"] == [code_path.resolve(strict=False)] assert artifacts["model_path"] == newer_stl.resolve(strict=False) assert artifacts["model_paths"] == [newer_stl.resolve(strict=False)] assert artifacts["output_paths"] == [] def test_extract_latest_artifacts_resolves_output_file_relative_to_workspace_root( tmp_path, ): workspace_dir = tmp_path / "workspace" / "demo_part" workspace_dir.mkdir(parents=True) code_path = workspace_dir / "model.py" model_path = workspace_dir / "part.stl" code_path.write_text("print('demo')\n", encoding="utf-8") model_path.write_text("solid demo\nendsolid demo\n", encoding="utf-8") messages = [ { "role": "assistant", "content": ( "Saved files\n" "<|code_file|>workspace/demo_part/model.py\n" "<|output_file|>./demo_part/part.stl" ), } ] artifacts = extract_latest_artifacts(messages, project_root=tmp_path) assert artifacts["code_path"] == code_path.resolve(strict=False) assert artifacts["code_paths"] == [code_path.resolve(strict=False)] assert artifacts["model_path"] == model_path.resolve(strict=False) assert artifacts["model_paths"] == [model_path.resolve(strict=False)] assert artifacts["output_paths"] == [model_path.resolve(strict=False)] def test_extract_latest_artifacts_resolves_output_file_relative_to_code_dir(tmp_path): workspace_dir = tmp_path / "workspace" / "demo_part" workspace_dir.mkdir(parents=True) code_path = workspace_dir / "model.py" model_path = workspace_dir / "part.stl" code_path.write_text("print('demo')\n", encoding="utf-8") model_path.write_text("solid demo\nendsolid demo\n", encoding="utf-8") messages = [ { "role": "assistant", "content": ( "Saved files\n" "<|code_file|>workspace/demo_part/model.py\n" "<|output_file|>./part.stl" ), } ] artifacts = extract_latest_artifacts(messages, project_root=tmp_path) assert artifacts["code_path"] == code_path.resolve(strict=False) assert artifacts["code_paths"] == [code_path.resolve(strict=False)] assert artifacts["model_path"] == model_path.resolve(strict=False) assert artifacts["model_paths"] == [model_path.resolve(strict=False)] assert artifacts["output_paths"] == [model_path.resolve(strict=False)] def test_extract_latest_artifacts_returns_manual_selection_candidates_in_recency_order( tmp_path, ): alpha_dir = tmp_path / "workspace" / "alpha" beta_dir = tmp_path / "workspace" / "beta" alpha_dir.mkdir(parents=True) beta_dir.mkdir(parents=True) alpha_code = alpha_dir / "model.py" beta_code = beta_dir / "model.py" alpha_model = alpha_dir / "alpha.stl" beta_model = beta_dir / "beta.stl" alpha_code.write_text("print('alpha')\n", encoding="utf-8") beta_code.write_text("print('beta')\n", encoding="utf-8") alpha_model.write_text("solid alpha\nendsolid alpha\n", encoding="utf-8") beta_model.write_text("solid beta\nendsolid beta\n", encoding="utf-8") messages = [ { "role": "assistant", "content": ( "<|code_file|>workspace/alpha/model.py\n" "<|output_file|>workspace/alpha/alpha.stl" ), }, { "role": "assistant", "content": ( "<|code_file|>workspace/beta/model.py\n" "<|output_file|>workspace/beta/beta.stl" ), }, ] artifacts = extract_latest_artifacts(messages, project_root=tmp_path) assert artifacts["code_path"] == beta_code.resolve(strict=False) assert artifacts["code_paths"] == [ beta_code.resolve(strict=False), alpha_code.resolve(strict=False), ] assert artifacts["model_path"] == beta_model.resolve(strict=False) assert artifacts["model_paths"] == [ beta_model.resolve(strict=False), alpha_model.resolve(strict=False), ] assert artifacts["output_paths"] == [ beta_model.resolve(strict=False), alpha_model.resolve(strict=False), ]