mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-11-14 09:01:22 +00:00
Retry empty Daily Paper frontmatter output
This commit is contained in:
parent
dded3ee4b8
commit
a721218df0
4 changed files with 47 additions and 3 deletions
|
|
@ -19,7 +19,7 @@ from .schema import AnalyzedPaper, DailyPaperMarkdownOutput
|
|||
# Number of papers selected, analyzed, and digested each run. Shared across steps.
|
||||
PAPER_COUNT = 3
|
||||
_STATE_PREFIX = "daily_paper_"
|
||||
_FRONTMATTER_PATTERN = re.compile(r"^---\s*\n.*?\n---(?:\s*\n|$)", re.DOTALL)
|
||||
_FRONTMATTER_PATTERN = re.compile(r"^---[ \t]*\n.*?^---[ \t]*(?:\n|$)", re.DOTALL | re.MULTILINE)
|
||||
_MARKDOWN_HEADING_PATTERN = re.compile(r"^#+\s*")
|
||||
_UNSAFE_FILENAME_CHARS = re.compile(r'[<>:"/\\|?*\x00-\x1f]')
|
||||
_CHINESE_PATTERN = re.compile(r"[\u3400-\u4dbf\u4e00-\u9fff]")
|
||||
|
|
@ -169,7 +169,6 @@ async def reserve_unique_note_path(
|
|||
|
||||
async def write_atomic(path: Path, content: str | bytes) -> None:
|
||||
"""Write atomically under the path lock, cleaning surrogate text first."""
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
lock = await get_path_lock(path)
|
||||
async with lock:
|
||||
payload = replace_surrogates(content) if isinstance(content, str) else content
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ class DailyPaperDigestStep(DailyPaperStep):
|
|||
{
|
||||
"name": title,
|
||||
"title": title,
|
||||
"description": output.desc.strip(),
|
||||
"description": output.desc,
|
||||
"kind": "daily-paper-brief",
|
||||
"date": day,
|
||||
"arxiv_ids": selected_ids,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import pytest
|
|||
from pydantic import BaseModel
|
||||
|
||||
from reme_daily_paper.analyze import DailyPaperAnalyzeStep
|
||||
from reme_daily_paper.base import markdown_output
|
||||
from reme_daily_paper.schema import PaperInfo, PaperPick
|
||||
from reme.components import ApplicationContext, RuntimeContext
|
||||
from reme.components.agent_wrapper import AsAgentWrapper
|
||||
|
|
@ -134,3 +135,46 @@ async def test_codex_json_parse_failure_gets_one_shorter_retry(tmp_path, monkeyp
|
|||
assert instruction not in thread.run.await_args_list[0].args[0]
|
||||
assert instruction in thread.run.await_args_list[1].args[0]
|
||||
downloader.download.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("empty_frontmatter", ["---\n---", "---\n---\n"])
|
||||
@pytest.mark.asyncio
|
||||
async def test_empty_frontmatter_retries_once_without_repeating_pdf_work(tmp_path, monkeypatch, empty_frontmatter):
|
||||
"""An empty frontmatter-only note triggers one shorter retry after one PDF extraction."""
|
||||
app = ApplicationContext(workspace_dir=str(tmp_path))
|
||||
valid = {"title": "论文摘要", "desc": "summary", "body": "Recovered result"}
|
||||
reply = AsyncMock(
|
||||
side_effect=[
|
||||
{"structured_output": {"title": "论文摘要", "desc": "summary", "body": empty_frontmatter}},
|
||||
{"structured_output": valid},
|
||||
],
|
||||
)
|
||||
step = DailyPaperAnalyzeStep(app_context=app)
|
||||
step.agent_wrapper = SimpleNamespace(reply=reply)
|
||||
step.context = RuntimeContext(daily_paper_run_date="2026-07-21")
|
||||
extraction_calls = []
|
||||
|
||||
def extract(*_args):
|
||||
extraction_calls.append(True)
|
||||
return "Evidence [p. 1]", 1, False
|
||||
|
||||
monkeypatch.setattr(step, "_extract_pdf_text_sync", extract)
|
||||
downloader = SimpleNamespace(download=AsyncMock())
|
||||
paper = PaperInfo(arxiv_id="2607.10001")
|
||||
pick = PaperPick(arxiv_id=paper.arxiv_id, reasoning="test")
|
||||
|
||||
result = await step._analyze_one(downloader, paper, pick, set())
|
||||
|
||||
note = (tmp_path / result.note_path).read_text(encoding="utf-8")
|
||||
assert "Recovered result" in note
|
||||
assert reply.await_count == 2
|
||||
downloader.download.assert_awaited_once()
|
||||
assert extraction_calls == [True]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("body", ["---\n---\nUseful note", "---\n---\n\nUseful note"])
|
||||
def test_content_after_empty_frontmatter_is_retained(body):
|
||||
"""Removing an empty frontmatter block must leave the Markdown body intact."""
|
||||
result = markdown_output({"structured_output": {"title": "Title", "desc": "Description", "body": body}})
|
||||
|
||||
assert result.body == "Useful note"
|
||||
|
|
|
|||
|
|
@ -224,6 +224,7 @@ def test_daily_paper_declares_runtime_dependencies() -> None:
|
|||
|
||||
assert not by_name["reme-ai"].extras
|
||||
assert Version("0.4.1.11") not in by_name["reme-ai"].specifier
|
||||
assert Version("0.4.1.12") not in by_name["reme-ai"].specifier
|
||||
assert Version("0.4.2.0") in by_name["reme-ai"].specifier
|
||||
assert "pypdf" in by_name
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue