feat: autonomous SOP refactor + helper.py with auto date/numbering
- Refactored autonomous_operation_sop.md with clearer path warnings and workflow - Added helper.py: complete_task() auto-prepends R-number + date to history - Updated scheduled_task_sop.md and web_setup_sop.md
This commit is contained in:
@@ -5,29 +5,35 @@
|
|||||||
|
|
||||||
授权你进行自主行动,只要不对环境造成副作用都可进行。
|
授权你进行自主行动,只要不对环境造成副作用都可进行。
|
||||||
|
|
||||||
|
## 启动(第一步)
|
||||||
|
- update_working_checkpoint: `自主行动|收尾时重读SOP | from autonomous_operation_sop.helper import *; set_todo()/complete_task(tasktitle, historyline, report_path)`
|
||||||
|
|
||||||
|
第二步:
|
||||||
|
```python
|
||||||
|
from autonomous_operation_sop.helper import *
|
||||||
|
print(get_history(40)) # 了解历史避免重复
|
||||||
|
print(get_todo()) # 查看待办
|
||||||
|
```
|
||||||
|
|
||||||
## 任务选择
|
## 任务选择
|
||||||
- 有 `./TODO.txt`(temp根目录)未完成条目 → 取**一条**,直接进入执行,其他条目下次执行
|
- 有未完成条目 → 取**一条**,直接进入执行,其他条目下次执行
|
||||||
- 无 TODO → 读 `autonomous_operation_sop/task_planning.md` 规划,下次执行
|
- 无 TODO → 读 `autonomous_operation_sop/task_planning.md` 规划,下次执行
|
||||||
- 不连续两次选相同子任务
|
- 不连续两次选相同子任务
|
||||||
|
- 价值公式:**「AI训练数据无法覆盖」×「对未来协作有持久收益」**
|
||||||
价值公式:**「AI训练数据无法覆盖」×「对未来协作有持久收益」**
|
|
||||||
|
|
||||||
## 执行
|
## 执行
|
||||||
|
- 选定任务后 update_working_checkpoint,将选中的TODO条目和执行注意事项 append 到 checkpoint 中
|
||||||
**启动**:
|
- 调用code_run准备结尾回调, script为handler._done_hooks.append("重读自主任务sop,检查你刚刚的收尾工作是否正确,不正确则改正"),_inline_eval=True (秘密参数)
|
||||||
- update_working_checkpoint: `自主行动|报告→./autonomous_reports/R{XX}_简短描述.md|≤30回合|收尾:重读sop,写报告+更新history+标记TODO | 报告严禁放错位置`
|
|
||||||
- 读 `./autonomous_reports/history.txt` 推断下一编号RXX + 了解历史避免重复
|
|
||||||
|
|
||||||
**执行**:
|
|
||||||
- ≤30回合,小步快跑,边探测边实验
|
- ≤30回合,小步快跑,边探测边实验
|
||||||
- 用临时脚本验证假设;禁只读即下结论,完整验证再写报告
|
- 用临时脚本验证假设;禁只读即下结论,完整验证再写报告
|
||||||
- 即使失败也记录实验过程和结果,失败报告同样有价值
|
- 即使失败也记录实验过程和结果,失败报告同样有价值
|
||||||
- 用户不在线,遇到需要决策的问题写入报告待审,不要卡住
|
- 用户不在线,遇到需要决策的问题写入报告待审,不要卡住
|
||||||
|
|
||||||
**收尾(三件事缺一不可)**:
|
**收尾(三件事缺一不可)**:
|
||||||
1. 写报告 `./autonomous_reports/R{XX}_简短描述.md`,格式简洁仅关键发现详述;若有记忆更新建议,附在报告末尾
|
0. 重读本sop
|
||||||
2. 更新 `./autonomous_reports/history.txt`(prepend一条:`RXX | 日期 | 类型 | 主题 | 结论`,严格单行,先读此文件头几行了解格式)
|
1. 在cwd写报告(文件名任意),若有记忆更新建议,附在报告末尾
|
||||||
3. 在 `./TODO.txt`(temp根目录)中将已完成条目标记为 `[x]`
|
2. `from/import helper; complete_task(tasktitle, historyline, report_path)` → 自动编号+移报告到 autonomous_reports/+prepend history(historyline 格式:`类型 | 主题 | 结论`,严格单行)
|
||||||
|
3. `set_todo()` 获取TODO路径 → 将已完成条目标记为 `[x]`
|
||||||
|
|
||||||
## 权限边界
|
## 权限边界
|
||||||
- 无需批准:只读探测、cwd内写操作/脚本实验
|
- 无需批准:只读探测、cwd内写操作/脚本实验
|
||||||
|
|||||||
143
memory/autonomous_operation_sop/helper.py
Normal file
143
memory/autonomous_operation_sop/helper.py
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
"""
|
||||||
|
autonomous_task.py - 自主行动任务管理API
|
||||||
|
放置: memory/autonomous_operation_sop/
|
||||||
|
用法: import autonomous_task (或 from autonomous_operation_sop import autonomous_task)
|
||||||
|
|
||||||
|
4个函数:
|
||||||
|
get_todo() → 返回TODO内容
|
||||||
|
get_history(n) → 返回最近n条历史
|
||||||
|
complete_task() → 移报告+编号+写history+返回改TODO指令
|
||||||
|
set_todo() → 返回TODO真实路径
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# ── 路径计算(基于模块自身位置) ──
|
||||||
|
_MODULE_DIR = Path(__file__).resolve().parent # memory/autonomous_operation_sop/
|
||||||
|
_MEMORY_DIR = _MODULE_DIR.parent # memory/
|
||||||
|
_AGENT_DIR = _MEMORY_DIR.parent # GenericAgent/
|
||||||
|
_TEMP_DIR = _AGENT_DIR / "temp" # GenericAgent/temp/
|
||||||
|
_REPORTS_DIR = _TEMP_DIR / "autonomous_reports"
|
||||||
|
_HISTORY_FILE = _REPORTS_DIR / "history.txt"
|
||||||
|
_TODO_FILE = _TEMP_DIR / "TODO.txt"
|
||||||
|
|
||||||
|
|
||||||
|
def _next_report_number() -> int:
|
||||||
|
"""扫 history.txt 第一行提取最大 RXX 编号,返回下一个"""
|
||||||
|
if not _HISTORY_FILE.exists():
|
||||||
|
return 1
|
||||||
|
with open(_HISTORY_FILE, "r", encoding="utf-8") as f:
|
||||||
|
content = f.read()
|
||||||
|
# 匹配所有 R 后跟数字的模式
|
||||||
|
nums = [int(m) for m in re.findall(r'R(\d+)', content)]
|
||||||
|
if not nums:
|
||||||
|
return 1
|
||||||
|
return max(nums) + 1
|
||||||
|
|
||||||
|
|
||||||
|
def get_todo() -> str:
|
||||||
|
"""返回 TODO.txt 的内容。若文件不存在返回提示。"""
|
||||||
|
if not _TODO_FILE.exists():
|
||||||
|
return f"[autonomous_task] TODO.txt 不存在,路径: {_TODO_FILE}"
|
||||||
|
with open(_TODO_FILE, "r", encoding="utf-8") as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
|
def get_history(n: int = 20) -> str:
|
||||||
|
"""返回 history.txt 的前 n 行(最新在前)。"""
|
||||||
|
if not _HISTORY_FILE.exists():
|
||||||
|
return f"[autonomous_task] history.txt 不存在,路径: {_HISTORY_FILE}"
|
||||||
|
with open(_HISTORY_FILE, "r", encoding="utf-8") as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
return "".join(lines[:n])
|
||||||
|
|
||||||
|
|
||||||
|
def set_todo(*args, **kwargs) -> str:
|
||||||
|
"""返回 TODO.txt 的真实绝对路径,供 agent/子agent 自行读写。"""
|
||||||
|
return f'路径: {str(_TODO_FILE)}'
|
||||||
|
|
||||||
|
|
||||||
|
def complete_task(taskname: str, historyline: str, report_path: str) -> str:
|
||||||
|
"""
|
||||||
|
完成任务的原子操作:
|
||||||
|
1. 移动 report_path → autonomous_reports/R{XX}_{taskname}.md(自动编号)
|
||||||
|
2. prepend historyline 到 history.txt(校验必须单行)
|
||||||
|
3. 返回字符串指示 agent 自己去改 TODO
|
||||||
|
|
||||||
|
Args:
|
||||||
|
taskname: 任务简短名称(用于报告文件名,如 "晨间简报")
|
||||||
|
historyline: 历史记录内容(必须单行,日期自动添加,如 "工程 | 晨间简报 | 完成7模块聚合")
|
||||||
|
report_path: agent 已写好的报告文件路径(绝对或相对于cwd)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
成功消息 + 改TODO指令,或错误消息
|
||||||
|
"""
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
# ── 校验 ──
|
||||||
|
if "\n" in historyline.strip():
|
||||||
|
return "[ERROR] historyline 必须是单行,不能包含换行符"
|
||||||
|
|
||||||
|
report = Path(report_path).resolve()
|
||||||
|
if not report.exists():
|
||||||
|
return f"[ERROR] 报告文件不存在: {report_path}"
|
||||||
|
|
||||||
|
if not _REPORTS_DIR.exists():
|
||||||
|
_REPORTS_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# ── 1. 移动报告 ──
|
||||||
|
rnum = _next_report_number()
|
||||||
|
# 清理 taskname 中的非法文件名字符
|
||||||
|
safe_name = re.sub(r'[<>:"/\\|?*]', '_', taskname).strip()
|
||||||
|
dest_name = f"R{rnum}_{safe_name}.md"
|
||||||
|
dest_path = _REPORTS_DIR / dest_name
|
||||||
|
|
||||||
|
try:
|
||||||
|
shutil.move(str(report), str(dest_path))
|
||||||
|
except Exception as e:
|
||||||
|
return f"[ERROR] 移动报告失败: {e}"
|
||||||
|
|
||||||
|
# ── 2. prepend history ──
|
||||||
|
# 自动加编号 + 日期(剥离 agent 可能已写的编号/日期,统一重建)
|
||||||
|
line = historyline.strip()
|
||||||
|
line = re.sub(r'^R\d+\s*\|\s*', '', line) # 剥离 R 编号
|
||||||
|
line = re.sub(r'^\d{4}-\d{2}-\d{2}\s*\|\s*', '', line) # 剥离日期
|
||||||
|
today = datetime.now().strftime('%Y-%m-%d')
|
||||||
|
line = f"R{rnum} | {today} | {line}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
existing = ""
|
||||||
|
if _HISTORY_FILE.exists():
|
||||||
|
with open(_HISTORY_FILE, "r", encoding="utf-8") as f:
|
||||||
|
existing = f.read()
|
||||||
|
with open(_HISTORY_FILE, "w", encoding="utf-8") as f:
|
||||||
|
f.write(line + "\n" + existing)
|
||||||
|
except Exception as e:
|
||||||
|
# 回滚:把报告移回去
|
||||||
|
try:
|
||||||
|
shutil.move(str(dest_path), str(report))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return f"[ERROR] 写入 history 失败: {e}(报告已回滚)"
|
||||||
|
|
||||||
|
# ── 3. 返回改 TODO 指令 ──
|
||||||
|
return (
|
||||||
|
f"✅ 完成!报告已保存: {dest_name}\n"
|
||||||
|
f"历史已记录: {line}\n"
|
||||||
|
f"👉 请在 {_TODO_FILE} 中将对应任务标记为 [x] R{rnum}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ── 快速自检 ──
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(f"TEMP_DIR: {_TEMP_DIR}")
|
||||||
|
print(f"REPORTS_DIR: {_REPORTS_DIR}")
|
||||||
|
print(f"HISTORY: {_HISTORY_FILE}")
|
||||||
|
print(f"TODO: {_TODO_FILE}")
|
||||||
|
print(f"Next R#: R{_next_report_number()}")
|
||||||
|
print(f"\n--- TODO ---\n{get_todo()[:200]}")
|
||||||
|
print(f"\n--- History (5) ---\n{get_history(5)}")
|
||||||
@@ -4,9 +4,10 @@
|
|||||||
|
|
||||||
## 任务JSON格式(*.json)
|
## 任务JSON格式(*.json)
|
||||||
```json
|
```json
|
||||||
{"schedule":"08:00", "repeat":"daily", "enabled":true, "prompt":"..."}
|
{"schedule":"08:00", "repeat":"daily", "enabled":true, "prompt":"...", "max_delay_hours":6}
|
||||||
```
|
```
|
||||||
repeat可选:daily | weekly | monthly | once | every_Nh(每N小时)| every_Nd(每N天)
|
repeat可选:daily | weekday | weekly | monthly | once | every_Nh(每N小时)| every_Nd(每N天)
|
||||||
|
max_delay_hours(可选,默认6):超过schedule多少小时后不再触发,防止开机太晚执行过时任务
|
||||||
|
|
||||||
## 触发流程
|
## 触发流程
|
||||||
1. scheduler.py(reflect/)每60秒轮询 sche_tasks/*.json
|
1. scheduler.py(reflect/)每60秒轮询 sche_tasks/*.json
|
||||||
@@ -15,6 +16,11 @@ repeat可选:daily | weekly | monthly | once | every_Nh(每N小时)| every
|
|||||||
4. **收到任务后第一件事**:用 update_working_checkpoint 记录报告目标文件路径,防止长任务执行中遗忘
|
4. **收到任务后第一件事**:用 update_working_checkpoint 记录报告目标文件路径,防止长任务执行中遗忘
|
||||||
5. 执行完毕后将报告写入上述路径(scheduler靠此文件判断今天已执行)
|
5. 执行完毕后将报告写入上述路径(scheduler靠此文件判断今天已执行)
|
||||||
|
|
||||||
|
## 日志与监控
|
||||||
|
- scheduler自动写日志到 `sche_tasks/scheduler.log`(触发/跳过/错误)
|
||||||
|
- `scheduler.health_check()` 返回所有任务状态列表(HEALTHY/OVERDUE/DISABLED/NEVER_RUN/ERROR)
|
||||||
|
- JSON解析错误、schedule格式错误、未知repeat类型均会记录日志
|
||||||
|
|
||||||
## 注意
|
## 注意
|
||||||
- once类型:执行一次后冷却100年(实际效果为永久跳过)
|
- once类型:执行一次后冷却100年(实际效果为永久跳过)
|
||||||
- 任务文件只管"干什么",报告路径由scheduler自动生成注入prompt
|
- 任务文件只管"干什么",报告路径由scheduler自动生成注入prompt
|
||||||
|
|||||||
@@ -50,6 +50,11 @@ browser = "chrome" if shutil.which("chrome") else "msedge" # Edge内置必存
|
|||||||
```
|
```
|
||||||
3. 提示用户在详情页中开启「允许运行用户脚本」开关。
|
3. 提示用户在详情页中开启「允许运行用户脚本」开关。
|
||||||
|
|
||||||
|
## 阶段 1.6:配置 Tampermonkey CSP 设置
|
||||||
|
**目的**:移除网站 CSP 头,使 web_execute_js 能在所有页面正常注入执行。
|
||||||
|
**路径**:TM 管理面板 → 设置 → 配置模式选「高级」→ 修改内容安全策略(CSP)头信息 → 选「全部移除」→ **点保存按钮**
|
||||||
|
- ⚠️ 高级设置不会自动保存,必须手动点页面底部的「保存」按钮,否则配置不生效
|
||||||
|
|
||||||
## 阶段二:安装 ljq_web_driver.user.js
|
## 阶段二:安装 ljq_web_driver.user.js
|
||||||
**脚本路径**: `../assets/ljq_web_driver.user.js`
|
**脚本路径**: `../assets/ljq_web_driver.user.js`
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user