* feat: add DSH memory integration and organize extensions * fix: support newer DSH release candidates * fix: address DSH integration review feedback * fix: handle DSH cross-day retry edge cases
12 KiB
Daily Paper Cookbook
Daily Paper selects three papers from the Hugging Face Papers weekly and monthly rankings, downloads their arXiv PDFs,
and produces detailed Chinese reading notes plus a roughly five-minute Chinese brief. The implementation lives in
reme/steps/cookbook/daily_paper/ and is assembled by
daily_cookbook.yaml.
Quick start
The workflow requires Python 3.11 or later, the core dependencies, an available AgentScope LLM, and network access to
Hugging Face Papers and arXiv.
python -m pip install -e ".[core]"
export LLM_API_KEY="your-api-key"
export LLM_MODEL_NAME="qwen3.7-plus"
export LLM_BASE_URL="https://your-provider.example/v1"
reme start config=daily_cookbook job=daily_paper
The built-in LLM component defaults to:
- model:
qwen3.7-plus - endpoint: no built-in
LLM_BASE_URL; set the OpenAI-compatible endpoint required by your provider - environment variables:
LLM_API_KEY,LLM_MODEL_NAME, andLLM_BASE_URL
Auto Fin and Daily Paper share this single default LLM and the default AgentScope wrapper. Daily Paper Select and
Analyze call the wrapper without tools, while Daily Paper Digest and Auto Fin Merge receive the read-only
memory_search and read ReMe job tools. The interactive dingtalk_wait step separately overrides the wrapper per
call with AgentScope bash and an explicit ReMe job allowlist.
The default workspace is reme_workspace/ beneath the process working directory. Override it with
DAILY_PAPER_WORKSPACE_DIR.
Pipeline
Hugging Face weekly/monthly rankings
│
▼
Collect ──► Rank ──► Select 3 ──► Analyze PDFs ──► Digest ──► DingTalk (optional)
│ │
├─ PDFs ├─ daily brief
└─ paper notes └─ day index
1. Collect
daily_paper_collect_step concurrently fetches:
- the Hugging Face weekly ranking for the run date's ISO week;
- the monthly ranking for the run date's calendar month; and
- Hugging Face Daily Papers for exactly the previous calendar day.
The weekly and monthly results are merged by arXiv ID while preserving both ranks. The step then excludes papers found
in yesterday's list or in the arxiv_id frontmatter of daily/<date>/*.md within the previous history_days.
If a Markdown file with kind: daily-paper-brief already exists and force=false, generation is skipped; the saved
brief can still proceed to DingTalk delivery. The job fails when no eligible papers remain.
2. Rank
daily_paper_rank_step uses reciprocal-rank fusion:
score = 1 / (rrf_k + monthly_rank)
+ weekly_weight / (rrf_k + weekly_rank)
A missing rank contributes zero. Papers are ordered by fused score, upvotes, and arXiv ID. The pool is capped at
candidate_limit, and Rank applies no topic preference.
3. Select
daily_paper_select_step sends candidate metadata to a tool-free AgentScope agent and requires exactly three items:
{"papers": [{"arxiv_id": "2601.01234", "reasoning": "A specific, verifiable reason"}]}
All IDs must be unique and belong to the candidate pool, and every reason must be non-empty. A validation failure is
returned to the agent for one retry. Only a non-empty topics value injects a personalized subject preference into the
selection prompt; it does not change the fixed count of three papers.
4. Analyze
daily_paper_analyze_step processes the selected papers in order:
- validates a modern
YYYY.NNNNorYYYY.NNNNNarXiv ID; - downloads the PDF to
resource/papers/<arxiv-id>.pdf; - reuses an existing target whose header is
%PDF-; - extracts paginated text with
pypdf, bounded bymax_pdf_pagesandmax_pdf_chars; - sends metadata, selection reasoning, and PDF text to a tool-free agent; and
- writes a Chinese note to
daily/<date>/<Chinese-title>.md.
Downloads use a temporary file and atomically replace the target only after validating the PDF header. They are also
bounded by max_pdf_bytes. There is no OCR fallback, so scanned or textless PDFs fail. When extraction is truncated,
the note records pdf_text_truncated: true in its frontmatter.
5. Digest
daily_paper_digest_step uses the three in-memory analyses as the factual source for the Chinese brief. It also
searches and, when needed, reads earlier daily notes to identify related coverage; those notes may only support
contextual wikilinks, not add facts about the current papers. The agent returns title, desc, and body. The code
then:
- strips model-generated YAML frontmatter if present;
- normalizes the Chinese title for use as a filename;
- keeps model-generated wikilinks only when they point to existing
daily/Markdown files dated before the run date; - deterministically appends wikilinks to all three source notes;
- writes
daily/<date>/<Chinese-brief-title>.md; and - rebuilds the
daily/<date>.mdday index.
Final response metadata includes the date, week/month scopes, selected arXiv IDs, selection reasons, note/PDF/brief paths, source counts, and exclusion counts.
6. DingTalk
The final dingtalk_markdown_send_step is optional. With no conversation IDs it is a no-op. When configured, it strips
frontmatter and sends the brief body to each group in order:
DINGTALK_APP_KEY=your-app-key
DINGTALK_APP_SECRET=your-app-secret
DINGTALK_ROBOT_CODE=your-robot-code
DINGTALK_CONVERSATION_IDS=cid-group-one,cid-group-two
A failed recipient does not prevent later attempts; the step reports a combined failure after trying every group.
Outputs
reme_workspace/
├── daily/
│ ├── YYYY-MM-DD.md
│ └── YYYY-MM-DD/
│ ├── <Chinese-paper-title>.md # three, kind: daily-paper-analysis
│ └── <Chinese-brief-title>.md # one, kind: daily-paper-brief
└── resource/
└── papers/
└── <arxiv-id>.pdf
Each successful generation writes three analysis notes and one brief. A forced rerun can leave unrelated or previously selected analysis notes in the same day directory; ReMe does not delete them as cleanup. Filenames come from the agent's Chinese titles. The implementation removes unsafe path characters and resolves title collisions. Markdown and PDF outputs are written through same-directory temporary files and atomic replacement.
Parameters and defaults
Public job parameters:
| Parameter | Default | Purpose |
|---|---|---|
date |
"" |
Run date; empty uses today in the app timezone, otherwise requires YYYY-MM-DD |
force |
false |
Regenerate even when the day's brief exists |
use_hf_mirror |
false |
Use the Hugging Face mirror from HF_MIRROR_URL, or https://hf-mirror.com when unset |
topics |
"" |
Topics to prioritize during selection |
weekly_weight |
0.7 |
Weekly contribution to RRF |
history_days |
30 |
Prior recommendation exclusion window |
Step-level settings on the daily_paper job:
| Setting | Default | Purpose |
|---|---|---|
candidate_limit |
20 |
Maximum candidates sent to Select |
rrf_k |
60 |
RRF constant |
hf_timeout |
600 seconds |
Timeout for one Hugging Face request |
hf_max_retries |
3 |
Maximum Hugging Face attempts |
pdf_timeout |
600 seconds |
arXiv PDF download timeout |
max_pdf_bytes |
52428800 |
PDF limit, 50 MiB |
max_pdf_pages |
35 |
Maximum extracted pages |
max_pdf_chars |
300000 |
Maximum extracted PDF characters sent to the agent |
Mirrors
The data clients use httpx's default environment handling, so HTTP_PROXY, HTTPS_PROXY, and NO_PROXY take effect
when present. The two data sources reach a mirror differently: Hugging Face is gated on the use_hf_mirror job
parameter, while arXiv is driven by its environment variable alone.
# The built-in daily_paper_cron job enables the mirror by default; set false to use the official service
DAILY_PAPER_USE_HF_MIRROR=false
# Read only when the manual or scheduled job enables the mirror; defaults to https://hf-mirror.com when unset
HF_MIRROR_URL=https://hf-mirror.com
# Optional override; the code defaults to https://arxiv.org when unset
ARXIV_MIRROR_URL=https://export.arxiv.org
# Path-prefixed relay URLs are also supported
# HF_MIRROR_URL=http://relay-host:18080/hf
# ARXIV_MIRROR_URL=http://relay-host:18080/arxiv
HF_MIRROR_URL must implement the /papers/..., /api/daily_papers, and /api/papers/... routes used by the current
client. ARXIV_MIRROR_URL must implement /pdf/<arxiv-id>. A path prefix in either base URL is preserved, and a
trailing slash is optional. There is no fallback chain: whichever base URL a client selects is the only one it tries.
Behavior change:
HF_MIRROR_URLused to redirect Hugging Face traffic on its own. It is now read only when the job runs withuse_hf_mirror=true; otherwise the official service is used and the client logs a warning that the variable was ignored. Passuse_hf_mirror=truefor manual requests. The built-indaily_paper_cronjob enables the mirror by default; setDAILY_PAPER_USE_HF_MIRROR=falseto make that scheduled job use the official service.
Running the workflow
Generate a brief for a specific date:
reme start \
config=daily_cookbook \
job=daily_paper \
date=2026-08-06 \
topics="Agent memory" \
history_days=30
Force a rerun; valid local PDFs are still reused:
reme start config=daily_cookbook job=daily_paper date=2026-08-06 force=true
Start the HTTP service and scheduled jobs:
reme start config=daily_cookbook
The built-in service listens on 127.0.0.1:8001. daily_paper_cron runs every day at 08:00 in the
Asia/Shanghai timezone, prioritizes the topic 大模型长期记忆, and uses the Hugging Face mirror by default. Set
DAILY_PAPER_USE_HF_MIRROR=false to use the official service. Override the bind address with DAILY_PAPER_HOST,
DAILY_PAPER_PORT, or startup arguments.
curl -s http://127.0.0.1:8001/daily_paper \
-H 'Content-Type: application/json' \
-d '{"date":"2026-08-06","force":false,"topics":"Agent memory"}'
Failures and reruns
- Hugging Face HTTP failures use exponential backoff up to
hf_max_retriesattempts; invalid response payloads fail immediately. - Fewer than three candidates, invalid agent selection, invalid/oversized/textless PDFs, or empty agent output stop the job.
- Papers are analyzed sequentially; PDFs and notes completed before a failure remain on disk.
force=trueregenerates the selected notes and the brief while reusing valid PDFs; it does not remove other notes already present in that day's directory.- The multi-file workflow is not transactional and has no global per-date execution lock.
Tests
The focused unit tests mock Hugging Face, arXiv, AgentScope, and DingTalk boundaries and do not call real services:
python -m pip install -e ".[dev,core]"
pytest tests/unit/test_daily_paper.py -v