diff --git a/Agent.md b/Agent.md index 804f010a..c67ce4e3 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.port; python -m emrg ``` -Python: `uv run pytest tests/ -v` (762) — import check: `uv run python -c "from emrg.client.app import run_client"` +Python: `uv run pytest tests/ -v` (764) — import check: `uv run python -c "from emrg.client.app import run_client"` GUI: `cd emrg/gui && npm test` (231: 44 daemon_client + 19 conn-manager + 22 app-commands + 109 renderer smoke + 15 i18n + 7 integration + 3 commands + 5 build-config + 7 gui-state) — 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/daemon.py b/emrg/server/daemon.py index f3065331..5e41c28b 100644 --- a/emrg/server/daemon.py +++ b/emrg/server/daemon.py @@ -1038,6 +1038,11 @@ def _build_system_prompt(self, session: Session | None = None) -> str: """ ctx: dict[str, Any] = {} + # ── Environment ── + ctx["current_time"] = datetime.now().astimezone().isoformat(timespec="seconds") + ctx["os_name"] = platform.system() + ctx["platform_detail"] = platform.platform() + # ── Working Directory ── if session: ctx["working_dir"] = str(session.cwd) diff --git a/emrg/server/prompts/system.j2 b/emrg/server/prompts/system.j2 index 88c86f4b..083d076a 100644 --- a/emrg/server/prompts/system.j2 +++ b/emrg/server/prompts/system.j2 @@ -11,6 +11,12 @@ You are EMRG, an evolving AI agent running as a micro-kernel daemon (emrgd). You - **write for new files**: use write for creating new files or full rewrites - **parallel calls**: when tools are independent, invoke them in parallel for speed +{% if current_time %} +**Current time**: `{{ current_time }}` +{% endif %} +{% if os_name %} +**Operating system**: `{{ os_name }}` ({{ platform_detail }}) +{% endif %} {% if working_dir %} **Working directory**: `{{ working_dir }}` {% endif %} diff --git a/tests/test_daemon.py b/tests/test_daemon.py index fb22505d..0dfa8d50 100644 --- a/tests/test_daemon.py +++ b/tests/test_daemon.py @@ -9,7 +9,9 @@ import asyncio import json +import re import tempfile +from datetime import datetime from pathlib import Path import yaml @@ -225,6 +227,42 @@ def test_context_section_no_files(tmp_path): assert result == [] +def test_system_prompt_environment_time_and_os(tmp_path): + """system.j2 renders Current time + Operating system env info. + + Rant 2026-08-13T14:01:46: agent must know "what time it is now" + (tz-aware local time, not UTC) and what platform it runs on. + """ + server = _make_server() + session = Session.create_with_id("env-test", tmp_path) + rendered = server._build_system_prompt(session) + + # Current time: tz-aware local ISO, seconds precision + assert "**Current time**: `" in rendered + m = re.search(r"\*\*Current time\*\*: `([^`]+)`", rendered) + assert m is not None + parsed = datetime.fromisoformat(m.group(1)) + assert parsed.tzinfo is not None # local tz-aware, never naive UTC + + # OS name + platform detail present + assert "**Operating system**: `" in rendered + assert "Darwin" in rendered or "Windows" in rendered or "Linux" in rendered + + # system.md debug output written + assert (session.dir_path / "system.md").exists() + md = (session.dir_path / "system.md").read_text(encoding="utf-8") + assert "Current time" in md and "Operating system" in md + + +def test_system_prompt_environment_without_session(tmp_path): + """Env info renders even with no session (current_time/os always known).""" + server = _make_server() + rendered = server._build_system_prompt() + assert "**Current time**: `" in rendered + assert "**Operating system**: `" in rendered + assert "**Working directory**" not in rendered + + def test_context_section_single_file(tmp_path): """When CLAUDE.md exists, it's returned as a dict entry.""" server = _make_server()