207 lines
7.6 KiB
Python
207 lines
7.6 KiB
Python
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</|code_file|>\n"
|
|
"<|output_file|>workspace/demo_part/part.stl</|output_file|>"
|
|
),
|
|
}
|
|
]
|
|
|
|
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</|code_file>\n"
|
|
"<|output_file|>./demo_part/part.stl</|output_file>"
|
|
),
|
|
}
|
|
]
|
|
|
|
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</|code_file|>",
|
|
}
|
|
]
|
|
|
|
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</|code_file|>\n"
|
|
"<|output_file|>./demo_part/part.stl</|output_file|>"
|
|
),
|
|
}
|
|
]
|
|
|
|
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</|code_file|>\n"
|
|
"<|output_file|>./part.stl</|output_file|>"
|
|
),
|
|
}
|
|
]
|
|
|
|
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</|code_file|>\n"
|
|
"<|output_file|>workspace/alpha/alpha.stl</|output_file|>"
|
|
),
|
|
},
|
|
{
|
|
"role": "assistant",
|
|
"content": (
|
|
"<|code_file|>workspace/beta/model.py</|code_file|>\n"
|
|
"<|output_file|>workspace/beta/beta.stl</|output_file|>"
|
|
),
|
|
},
|
|
]
|
|
|
|
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),
|
|
]
|