From d80d59d581c2135f8bfb5e9da9575324a950d3fd Mon Sep 17 00:00:00 2001 From: EMRG Evolution Date: Mon, 24 Aug 2026 22:16:40 +0800 Subject: [PATCH] emrg: task prompts: support per-task extra_prompt from tasks.yml config (rant 2026-08-24T21:59:15) --- Agent.md | 2 +- emrg/server/evolution_prompt.md | 6 ++++++ emrg/server/journal_prompt.md | 6 ++++++ emrg/server/open_source_prompt.md | 6 ++++++ emrg/server/paper_prompt.md | 6 ++++++ emrg/server/promote_prompt.md | 6 ++++++ tests/test_scheduler.py | 35 +++++++++++++++++++++++++++++++ 7 files changed, 66 insertions(+), 1 deletion(-) diff --git a/Agent.md b/Agent.md index 2f668b78..1d60a245 100644 --- a/Agent.md +++ b/Agent.md @@ -118,7 +118,7 @@ Community needs voiced in HN agent-UI discussions map directly to EMRG's design: pkill -f "emrg.server"; rm -f ~/.emrg/emrgd.token; python -m emrg ``` -Python: `uv run pytest tests/ -v` (1050) — import check: `uv run python -c "from emrg.client.app import run_client"` +Python: `uv run pytest tests/ -v` (1051) — import check: `uv run python -c "from emrg.client.app import run_client"` GUI: `cd emrg/gui && npm test` (259: 45 daemon_client + 20 conn-manager + 22 app-commands + 129 renderer smoke + 15 i18n + 8 integration + 3 commands + 8 build-config + 7 gui-state + 2 tool-group) — syntax: `node --check main.js preload.js daemon_client.js renderer/js/*.js` CI: `uv run pytest` (ubuntu + **windows-2025 matrix** — Windows pytest 回归在 PR CI 即失败,v0.2.29 教训 #725) + GUI tests + **actionlint workflow lint** (`rhysd/actionlint@v1.7.12` gate, #444 — workflow 解析错误在 PR CI 即失败,如 `if:` secrets 上下文) Re-trigger: `scripts/re-trigger-ci.sh [branch]` (workflow_dispatch, #527 — 替代空 commit 重触发:Actions outage 会整段丢弃 push 事件,dispatch 走 API 路径不受影响) diff --git a/emrg/server/evolution_prompt.md b/emrg/server/evolution_prompt.md index b922f192..b340ed46 100644 --- a/emrg/server/evolution_prompt.md +++ b/emrg/server/evolution_prompt.md @@ -13,6 +13,12 @@ You are EMRG's self-evolution module. **Every cycle you MUST fully execute the " - Local source: `{{ local_source }}` - Session ID: `{{ session_id }}` +{% if task.extra_prompt %} +## Task-specific Instructions (extra_prompt from tasks.yml) + +{{ task.extra_prompt }} +{% endif %} + --- ### 🌐 Language Policy (global, applies to every cycle) diff --git a/emrg/server/journal_prompt.md b/emrg/server/journal_prompt.md index 9a6ac66b..df540919 100644 --- a/emrg/server/journal_prompt.md +++ b/emrg/server/journal_prompt.md @@ -13,6 +13,12 @@ You are EMRG's journal participation module for **SILICON SCIENCE: Computer Scie - Instance registry: `{{ source_dir }}/INSTANCES.md`(期刊仓库内,跨机器可见) - **Current time: `{{ timestamp }}`({{ current_time_human }})** — 判断"近 6 个月/今年"科研热点、arXiv 时间窗、会议周期的时间锚 +{% if task.extra_prompt %} +## Task-specific Instructions (extra_prompt from tasks.yml) + +{{ task.extra_prompt }} +{% endif %} + --- ### 0. Preparation (MUST run first every cycle) diff --git a/emrg/server/open_source_prompt.md b/emrg/server/open_source_prompt.md index 5e082b46..8322cb57 100644 --- a/emrg/server/open_source_prompt.md +++ b/emrg/server/open_source_prompt.md @@ -12,6 +12,12 @@ You are EMRG's open-source participation module. **Every cycle you MUST fully ex - Session ID: `{{ session_id }}` - State file: `{{ evolution_cwd }}/open_source_{{ owner }}_{{ repo }}_state.md` +{% if task.extra_prompt %} +## Task-specific Instructions (extra_prompt from tasks.yml) + +{{ task.extra_prompt }} +{% endif %} + --- ### 0. Preparation (MUST run first every cycle) diff --git a/emrg/server/paper_prompt.md b/emrg/server/paper_prompt.md index 379120ee..b81ee448 100644 --- a/emrg/server/paper_prompt.md +++ b/emrg/server/paper_prompt.md @@ -9,6 +9,12 @@ You are EMRG's paper writing module. **Every writing session MUST fully execute - Session ID: `{{ session_id }}` - ⚠️ Note: the cycle counter resets to 1 after a daemon restart — **it does NOT represent the true historical run count**. Determine "is this the first run" from the state file `paper_state.md` and the project files instead. +{% if task.extra_prompt %} +## Task-specific Instructions (extra_prompt from tasks.yml) + +{{ task.extra_prompt }} +{% endif %} + --- ### 0. Phase Assessment (MUST run first every cycle) diff --git a/emrg/server/promote_prompt.md b/emrg/server/promote_prompt.md index 0aeb5b53..86f7ef1e 100644 --- a/emrg/server/promote_prompt.md +++ b/emrg/server/promote_prompt.md @@ -2,6 +2,12 @@ You are EMRG's community promotion module. **Every cycle you MUST fully execute the "Prepare → Participatory Four Steps → Reflect" flow, without skipping any step.** +{% if task.extra_prompt %} +## Task-specific Instructions (extra_prompt from tasks.yml) + +{{ task.extra_prompt }} +{% endif %} + ### Mission & Values (accountability — read first) **Mission**: promotion exists so that **{{ project.name }} is discovered and adopted by the people who need it**. Content quality is a **means** — the end is **discoverability and growth**. You are accountable for **results** (is the project actually being discovered?), not for the actions you performed (how many comments you posted). diff --git a/tests/test_scheduler.py b/tests/test_scheduler.py index 572f14cd..51df6ef6 100644 --- a/tests/test_scheduler.py +++ b/tests/test_scheduler.py @@ -1044,6 +1044,41 @@ def test_open_source_template_allow_self_merge_conditional(): assert "**overridden**" not in out_false +def test_task_extra_prompt_conditional_all_templates(): + """Rant 2026-08-24T21:59:15: tasks.yml config extra_prompt must inject into + every builtin task prompt (evolution/paper/open-source/promote/journal) near + the top; tasks WITHOUT extra_prompt render unchanged (no section, no residue). + + Positive AND negative states both validated (#455 lesson). + """ + import jinja2 + + env = jinja2.Environment(undefined=jinja2.Undefined) + server_dir = Path(__file__).resolve().parent.parent / "emrg" / "server" + base = dict( + instance_id="test", host_name="host", uptime="0h 0m", + repo_url="https://github.com/x/y.git", owner="x", repo="y", + local_source="/tmp/os", source_dir="/tmp/os", session_id="s1", + evolution_cwd="/tmp/evo", timestamp="20260824", + current_time_human="2026-08-24 22:00", + project={"name": "x"}, evolution_count=0, + git_path="git", gh_path="gh", + ) + extra = "插件开发(plugin)也是对本项目的合法贡献,不应被排除在贡献范围之外" + heading = "Task-specific Instructions (extra_prompt from tasks.yml)" + for name in ("evolution_prompt.md", "paper_prompt.md", "open_source_prompt.md", + "promote_prompt.md", "journal_prompt.md"): + tpl = env.from_string((server_dir / name).read_text(encoding="utf-8")) + # positive: extra_prompt configured → injected near the top + out = tpl.render(task={"extra_prompt": extra, "role": "committer"}, **base) + assert heading in out, f"{name}: 条件节应渲染" + assert extra in out, f"{name}: extra_prompt 文本应注入 prompt" + # negative: absent → no section, no residue + out2 = tpl.render(task={"role": "committer"}, **base) + assert heading not in out2, f"{name}: 未配置 extra_prompt 不得出现条件节" + assert extra not in out2, f"{name}: 未配置 extra_prompt 不得注入文本" + + def test_open_source_template_never_stashes_host_work(): """Rant 2026-08-20T11:58:27 (host data-loss report): a dirty working tree must run the cycle read-only — the prompt must never instruct stashing /