From bc5d1eafaf7364e7364dca9d7fda3c08c9a26e5c Mon Sep 17 00:00:00 2001 From: Liang Jiaqing Date: Mon, 30 Mar 2026 15:02:57 +0800 Subject: [PATCH] feat: add --bg/--input flags to agentmain, rename & simplify subagent SOP --- agentmain.py | 21 +++++++++++++++-- memory/{subagent_sop.md => subagent.md} | 31 +++++++------------------ 2 files changed, 28 insertions(+), 24 deletions(-) rename memory/{subagent_sop.md => subagent.md} (61%) diff --git a/agentmain.py b/agentmain.py index 9df3a5d..57dd6ce 100644 --- a/agentmain.py +++ b/agentmain.py @@ -151,17 +151,34 @@ if __name__ == '__main__': parser.add_argument('--scheduled', action='store_true', help='计划任务轮询模式') parser.add_argument('--task', metavar='IODIR', help='一次性任务模式(文件IO)') parser.add_argument('--reflect', metavar='SCRIPT', help='反射模式:加载监控脚本,check()触发时发任务') + parser.add_argument('--input', help='任务内容') parser.add_argument('--llm_no', type=int, default=0, help='LLM编号') + parser.add_argument('--bg', action='store_true', help='后台自举: spawn自身去掉--bg, print PID, exit') args = parser.parse_args() + if args.bg: + import subprocess, platform + cmd = [sys.executable, os.path.abspath(__file__)] + [a for a in sys.argv[1:] if a != '--bg'] + d = os.path.join(script_dir, f'temp/{args.task}'); os.makedirs(d, exist_ok=True) + p = subprocess.Popen(cmd, cwd=script_dir, + creationflags=0x08000000 if platform.system() == 'Windows' else 0, + stdout=open(os.path.join(d, 'stdout.log'), 'w', encoding='utf-8'), + stderr=open(os.path.join(d, 'stderr.log'), 'w', encoding='utf-8')) + print(p.pid); sys.exit(0) + agent = GeneraticAgent() agent.next_llm(args.llm_no) agent.verbose = False threading.Thread(target=agent.run, daemon=True).start() if args.task: - d = os.path.join(script_dir, f'temp/{args.task}'); rp = os.path.join(d, 'reply.txt'); nround = '' - with open(os.path.join(d, 'input.txt'), encoding='utf-8') as f: raw = f.read() + d = os.path.join(script_dir, f'temp/{args.task}'); nround = '' + rp = os.path.join(d, 'reply.txt'); infile = os.path.join(d, 'input.txt') + if args.input: + os.makedirs(d, exist_ok=True) + import glob; [os.remove(f) for f in glob.glob(os.path.join(d, 'output*.txt'))] + with open(infile, 'w', encoding='utf-8') as f: f.write(args.input) + with open(infile, encoding='utf-8') as f: raw = f.read() while True: dq = agent.put_task(raw, source='task') while 'done' not in (item := dq.get(timeout=120)): diff --git a/memory/subagent_sop.md b/memory/subagent.md similarity index 61% rename from memory/subagent_sop.md rename to memory/subagent.md index 828b02f..6526b1e 100644 --- a/memory/subagent_sop.md +++ b/memory/subagent.md @@ -2,32 +2,19 @@ ## Task Mode 文件IO协议 -- 目录:`temp/{task_name}/`(相对代码根GenericAgent/),主agent cwd在temp/时即 `./{task_name}/` -- 启动:`python agentmain.py --task {task_name} [--llm_no N]`(cwd=代码根),其中agentmain.py位于代码根目录 -- 流程:写 input.txt → 启动 → 轮询 output.txt → 读回复 → 写 reply.txt 继续 → 不写则5min自动退出 -- input.txt原则:写目标+约束,可指定SOP名。禁写具体实现步骤——除非主agent已读过该SOP确认正确。凭印象猜的步骤会误导subagent -- **input.txt长度红线**:input.txt必须精简。只写目标+约束+关键参数。大量数据给路径让subagent自己读,禁止入input.txt -- output.txt:首轮对话的流式输出(持续append),用mtime/size判断更新 -- output1.txt, output2.txt...:reply后各轮的流式输出(递增编号),同样持续append - -## 后台调用要点 +- 目录:`temp/{task_name}/`(相对代码根),主agent cwd在temp/时即 `./{task_name}/` +- 启动:`python agentmain.py --task {name} [--input "内容"] [--bg] [--llm_no N]`(cwd=代码根) + - `--input`:自动建目录+清旧output+写input.txt + - `--bg`:自举后台(Popen自身去掉--bg → print PID → exit) +- 流程:启动 → 轮询 output.txt(`[ROUND END]`=该轮完成)→ 写 reply.txt 继续 → 不写则5min退出 +- output1/2/3.txt:reply后各轮输出(递增编号),同样append+`[ROUND END]` +- input.txt:目标+约束,可指定SOP名。禁写具体步骤(除非已读SOP确认)。大量数据给路径禁塞入 +- --bg启动瞬间返回,可同一code_run内sleep后poll;非--bg方式禁止合并启动+轮询 ```python -task_dir = os.path.join(agent_root, 'temp', task_name) -creation_flags = 0x08000000 if platform.system() == 'Windows' else 0 -proc = subprocess.Popen( - [sys.executable, 'agentmain.py', '--task', task_name], - cwd=agent_root, creationflags=creation_flags, - stdout=open(os.path.join(task_dir, 'stdout.log'), 'w', encoding='utf-8'), - stderr=open(os.path.join(task_dir, 'stderr.log'), 'w', encoding='utf-8')) +pid = os.popen(f'python {agent_root}/agentmain.py --task {name} --input "{prompt}" --bg').read().strip() ``` -- 必须 Popen,禁止 subprocess.run(会阻塞) -- stdout.log/stderr.log 用于调试subagent卡死、LLM调用失败等问题 -- 文件统一 UTF-8,subagent 无 reply 5min 自动退出无需清理 -- **禁止合并启动+轮询到同一个code_run**——会阻塞自己。启动Popen立即返回,下一轮再poll output.txt。这是并行的前提 -- 新建/复用任务目录时,先删除旧 output*.txt(否则会读到上次结果误判完成) - ## 场景1:测试模式 - 行为验证 **用途**:观察agent真实行为,修正RULES/L2/L3/SOP **流程**:创建test_path/写input.txt→启动subagent→轮询output.txt(2秒间隔)→验证→清理重复