mirror of
https://github.com/HKUDS/OpenSpace.git
synced 2026-09-09 22:31:03 +00:00
Merge 23c83910a5 into 38277815ed
This commit is contained in:
commit
a7a76460ba
3 changed files with 50 additions and 4 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -51,6 +51,7 @@ tests/skill_engine/*
|
|||
!tests/skill_engine/test_evolver_length_recovery.py
|
||||
!tests/skill_engine/test_evolution_retry_idempotency.py
|
||||
!tests/skill_engine/test_analyzer_length_recovery.py
|
||||
!tests/skill_engine/test_detect_patch_type_prose.py
|
||||
!tests/skill_engine/decision/
|
||||
tests/skill_engine/decision/*
|
||||
!tests/skill_engine/decision/test_analysis_adapter.py
|
||||
|
|
|
|||
|
|
@ -482,11 +482,14 @@ def detect_patch_type(content: str) -> PatchType:
|
|||
if "*** Begin Files" in content:
|
||||
return PatchType.FULL
|
||||
|
||||
# Detect bare *** File: markers (no *** Begin Files envelope).
|
||||
# Must appear at line start; require at least one to look structural.
|
||||
file_header_hits = _FILE_HEADER_RE.findall(content)
|
||||
if file_header_hits:
|
||||
# ≥2 File: markers, or one at content start with a body (docstring rule 3).
|
||||
file_headers = list(_FILE_HEADER_RE.finditer(content))
|
||||
if len(file_headers) >= 2:
|
||||
return PatchType.FULL
|
||||
if len(file_headers) == 1:
|
||||
match = file_headers[0]
|
||||
if not content[: match.start()].strip() and content[match.end() :].strip():
|
||||
return PatchType.FULL
|
||||
|
||||
if "<<<<<<< SEARCH" in content:
|
||||
return PatchType.DIFF
|
||||
|
|
@ -527,6 +530,10 @@ def parse_multi_file_full(content: str) -> Dict[str, str]:
|
|||
# No multi-file markers — treat entire content as SKILL.md
|
||||
return {SKILL_FILENAME: content}
|
||||
|
||||
# Single mid-document *** File: is prose/example text, not multi-file.
|
||||
if len(headers) == 1 and stripped[: headers[0].start()].strip():
|
||||
return {SKILL_FILENAME: content}
|
||||
|
||||
files: Dict[str, str] = {}
|
||||
for i, match in enumerate(headers):
|
||||
file_path = match.group(1).strip()
|
||||
|
|
|
|||
38
tests/skill_engine/test_detect_patch_type_prose.py
Normal file
38
tests/skill_engine/test_detect_patch_type_prose.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
"""Regression: mid-document *** File: prose must not drop SKILL.md."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from openspace.skill_engine.patch import (
|
||||
PatchType,
|
||||
create_skill,
|
||||
detect_patch_type,
|
||||
parse_multi_file_full,
|
||||
)
|
||||
|
||||
|
||||
def test_detect_patch_type_ignores_single_mid_document_file_marker():
|
||||
content = "# My Skill\n\n*** File: helper.sh\n#!/bin/bash\necho hi\n"
|
||||
assert detect_patch_type(content) == PatchType.FULL
|
||||
parsed = parse_multi_file_full(content)
|
||||
assert list(parsed.keys()) == ["SKILL.md"]
|
||||
assert "*** File: helper.sh" in parsed["SKILL.md"]
|
||||
|
||||
|
||||
def test_create_skill_keeps_skill_md_when_file_marker_is_prose(tmp_path: Path):
|
||||
content = "# My Skill\n\n*** File: helper.sh\n#!/bin/bash\necho hi\n"
|
||||
result = create_skill(tmp_path / "s", content)
|
||||
assert result.ok
|
||||
skill_md = tmp_path / "s" / "SKILL.md"
|
||||
assert skill_md.is_file()
|
||||
assert "*** File: helper.sh" in skill_md.read_text()
|
||||
assert not (tmp_path / "s" / "helper.sh").exists()
|
||||
|
||||
|
||||
def test_detect_patch_type_accepts_structural_multi_file_at_start():
|
||||
content = "*** File: SKILL.md\n# Skill\n\n*** File: helper.sh\n#!/bin/bash\necho hi\n"
|
||||
assert detect_patch_type(content) == PatchType.FULL
|
||||
parsed = parse_multi_file_full(content)
|
||||
assert "SKILL.md" in parsed
|
||||
assert "helper.sh" in parsed
|
||||
Loading…
Add table
Reference in a new issue