From 5c9f827357e9bf814dbd6b52d19e4e57178144de Mon Sep 17 00:00:00 2001 From: wuyang <5700876+banisherwy@user.noreply.gitee.com> Date: Sun, 26 Jul 2026 16:35:58 +0800 Subject: [PATCH] fix: require executable source for Work reports --- agent_platform/runtime/loop.py | 21 +++++++++++++++++++++ tests/test_agent_loop.py | 9 +++++++++ 2 files changed, 30 insertions(+) diff --git a/agent_platform/runtime/loop.py b/agent_platform/runtime/loop.py index f273c7e..f1ce859 100644 --- a/agent_platform/runtime/loop.py +++ b/agent_platform/runtime/loop.py @@ -37,6 +37,8 @@ successful tool result from this run. For scripts, reports, code, and other deli files under /workspace, inspect them after writing, run relevant checks, and cite their exact paths. For a code-and-report task, follow this order: write a real source file, read it, run that exact source file with a complete command, write the report using only the measured output, then read the report. +The executable source and the report must be separate files: run the `.py`, `.js`, or other real +source file, never a Markdown, text, JSON, CSV, YAML, or other documentation/data file. Write source files with real line breaks rather than literal `\\n` escape sequences. If any command fails, inspect the failure, repair the underlying problem, and successfully rerun the relevant check; never replace failed output with invented numbers, placeholders, or a hand-written success report. @@ -57,6 +59,12 @@ INTERACTIVE_ONLY_COMMAND = re.compile( r"^(?:python(?:3(?:\.\d+)?)?|ipython|node|bash|sh|zsh|fish|jupyter(?:\s+(?:console|lab|notebook))?)\s*$", re.IGNORECASE, ) +PYTHON_NON_SOURCE_TARGET = re.compile( + r"(?:^|[;&|]\s*)python(?:3(?:\.\d+)?)?\s+" + r"(?!-[cm]\b)(?:-[A-Za-z]+(?:=\S+)?\s+)*" + r"[\"']?[^\"'\s;&|]+\.(?:csv|json|md|rst|txt|ya?ml)[\"']?(?=\s|$|[;&|])", + re.IGNORECASE, +) ARTIFACT_REQUEST = re.compile( r"(写|创建|生成|修改|实现|重构|修复|开发|报告|脚本|文件|代码|网页|项目|" r"\b(?:write|create|generate|modify|implement|refactor|fix|build|report|script|file|code)\b)", @@ -353,6 +361,17 @@ def python_source_error(arguments: dict[str, Any]) -> str | None: return None +def non_source_execution_error(arguments: dict[str, Any]) -> str | None: + command = str(arguments.get("command", "")).strip() + if not PYTHON_NON_SOURCE_TARGET.search(command): + return None + return ( + "Refused to execute a documentation or data file with Python. Create a separate valid `.py` " + "source file, read it, run that exact source file with `python3 .py`, and only then write " + "or update the report from the measured output." + ) + + def is_substantive_execution(name: str, arguments: dict[str, Any]) -> bool: if name == "start_process": return True @@ -822,6 +841,8 @@ class AgentLoop: result = {"ok": False, "error": f"Unknown tool: {name}"} elif read_only and name not in READ_ONLY_TOOL_NAMES: result = {"ok": False, "error": f"Tool {name} is not available to a read-only delegate"} + elif name in {"exec", "start_process"} and (target_error := non_source_execution_error(arguments)): + result = {"ok": False, "error": target_error} elif name in {"exec", "start_process"} and INTERACTIVE_ONLY_COMMAND.fullmatch( str(arguments.get("command", "")).strip() ): diff --git a/tests/test_agent_loop.py b/tests/test_agent_loop.py index 7d48e45..94135af 100644 --- a/tests/test_agent_loop.py +++ b/tests/test_agent_loop.py @@ -10,6 +10,7 @@ from agent_platform.models import get_model_spec from agent_platform.runtime.loop import ( AgentLoop, is_substantive_execution, + non_source_execution_error, normalize_write_file_content, python_source_error, select_tool_specs, @@ -59,6 +60,14 @@ def test_invalid_complete_python_source_is_detected_before_write() -> None: assert python_source_error({"path": "benchmark.py", "content": "print('ok')\n"}) is None +def test_python_cannot_execute_documentation_or_data_files() -> None: + assert non_source_execution_error({"command": "python3 SortingReport.md"}) is not None + assert non_source_execution_error({"command": "cd /workspace && python report.json"}) is not None + assert non_source_execution_error({"command": "python3 benchmark.py"}) is None + assert non_source_execution_error({"command": "python3 -m pytest"}) is None + assert non_source_execution_error({"command": "python3 -c 'print(1)' "}) is None + + def test_read_only_shell_commands_do_not_satisfy_execution_evidence() -> None: assert not is_substantive_execution("exec", {"command": "cat report.txt"}) assert not is_substantive_execution("exec", {"command": "sed -n '1,20p' script.py"})