diff --git a/agentmain.py b/agentmain.py
index 08b78e09..676ecd0c 100644
--- a/agentmain.py
+++ b/agentmain.py
@@ -1,4 +1,4 @@
-import os, sys, threading, queue, time, json, re, random, locale
+import os, sys, threading, queue, time, json, re, random, locale, glob
os.environ.setdefault('GA_LANG', 'zh' if any(k in (locale.getlocale()[0] or '').lower() for k in ('zh', 'chinese')) else 'en')
if sys.stdout is None: sys.stdout = open(os.devnull, "w")
elif hasattr(sys.stdout, 'reconfigure'): sys.stdout.reconfigure(errors='replace')
@@ -178,8 +178,6 @@ class GenericAgent:
if self.inc_out and last_pos < len(full_resp):
display_queue.put({'next': full_resp[last_pos:], 'source': source,
'turn': curr_turn, 'outputs': turn_resps[-2:]})
- #if '' in full_resp: full_resp = full_resp.replace('', '\n\n')
- #if '' in full_resp: full_resp = re.sub(r'\s*(.*?)\s*', r'\n````\n\n\1\n\n````', full_resp, flags=re.DOTALL)
display_queue.put({'done': full_resp, 'source': source, 'turn': curr_turn, 'outputs': turn_resps.copy()})
self.history = handler.history_info
except Exception as e:
@@ -198,6 +196,7 @@ if __name__ == '__main__':
from datetime import datetime
parser = argparse.ArgumentParser()
parser.add_argument('--task', metavar='IODIR', help='一次性任务模式,先看subagent.md')
+ parser.add_argument('--func', metavar='PROMPT_FILE', help='纯函数模式:读prompt文件→结果写prompt.out.txt→退出')
parser.add_argument('--reflect', metavar='SCRIPT', help='反射模式:加载监控脚本,check()触发时发任务')
parser.add_argument('--input', help='prompt')
parser.add_argument('--llm_no', type=int, default=0)
@@ -206,14 +205,17 @@ if __name__ == '__main__':
args, _unknown = parser.parse_known_args()
_reflect_args = dict(zip([k.lstrip('-') for k in _unknown[::2]], _unknown[1::2])) if _unknown else {}
- if args.task and not args.nobg:
+ if (args.func or args.task) and not args.nobg:
import subprocess, platform
cmd = [sys.executable, os.path.abspath(__file__)] + [a for a in sys.argv[1:]] + ['--nobg']
- d = os.path.join(script_dir, f'temp/{args.task}'); os.makedirs(d, exist_ok=True)
+ if args.task:
+ d = os.path.join(script_dir, f'temp/{args.task}'); os.makedirs(d, exist_ok=True)
+ out = open(os.path.join(d, 'stdout.log'), 'w', encoding='utf-8')
+ err = open(os.path.join(d, 'stderr.log'), 'w', encoding='utf-8')
+ else: out, err = subprocess.DEVNULL, subprocess.DEVNULL
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'))
+ stdout=out, stderr=err)
print('PID:', p.pid); sys.exit(0)
agent = GeneraticAgent()
@@ -222,31 +224,35 @@ if __name__ == '__main__':
threading.Thread(target=agent.run, daemon=True).start()
if args.task:
- agent.peer_hint = False
- agent.force_non_stream = True
agent.task_dir = d = os.path.join(script_dir, f'temp/{args.task}'); nround = ''
- infile = os.path.join(d, 'input.txt')
+ infile = os.path.join(d, 'input.txt'); outfile = f'{d}/output{nround}.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'))]
+ [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)
if (fh := consume_file(d, '_history.json')): agent.llmclient.backend.history = json.loads(fh)
+ elif args.func:
+ infile = args.func; outfile = os.path.splitext(args.func)[0] + '.out.txt'
+
+ if args.func or args.task:
+ agent.peer_hint = False
with open(infile, encoding='utf-8') as f: raw = f.read()
while True:
- dq = agent.put_task(raw, source='task')
+ dq = agent.put_task(raw, source='func' if args.func else 'task')
while 'done' not in (item := dq.get(timeout=1200)):
- if 'next' in item and random.random() < 0.95: # 概率写一次中间结果
- with open(f'{d}/output{nround}.txt', 'w', encoding='utf-8') as f: f.write(item.get('next', ''))
- with open(f'{d}/output{nround}.txt', 'w', encoding='utf-8') as f: f.write(item['done'] + '\n\n[ROUND END]\n')
+ if 'next' in item:
+ with open(outfile, 'w', encoding='utf-8') as f: f.write(item.get('next', ''))
+ with open(outfile, 'w', encoding='utf-8') as f: f.write(item['done'] + '\n\n[ROUND END]\n')
+ if not args.task: break
consume_file(d, '_stop') # 已经成功停下来了,避免打断下次reply
for _ in range(300): # 等reply.txt,10分钟超时
time.sleep(2)
if (raw := consume_file(d, 'reply.txt')): break
else: break
nround = nround + 1 if isinstance(nround, int) else 1
+ outfile = f'{d}/output{nround}.txt'
elif args.reflect:
agent.peer_hint = False
- agent.force_non_stream = True
import importlib.util
spec = importlib.util.spec_from_file_location('reflect_script', args.reflect)
mod = importlib.util.module_from_spec(spec); spec.loader.exec_module(mod)
diff --git a/frontends/desktop/src-tauri/tauri.conf.json b/frontends/desktop/src-tauri/tauri.conf.json
index 5681ffa1..e74082c1 100644
--- a/frontends/desktop/src-tauri/tauri.conf.json
+++ b/frontends/desktop/src-tauri/tauri.conf.json
@@ -17,7 +17,7 @@
"width": 1280,
"height": 800,
"resizable": true,
- "maximized": true,
+ "maximized": false,
"visible": false,
"url": "loading.html"
},
diff --git a/memory/computer_use.md b/memory/computer_use.md
index 2e5340c4..a6efa700 100644
--- a/memory/computer_use.md
+++ b/memory/computer_use.md
@@ -12,7 +12,8 @@
| 3 vision(VLM) | 2仍不足时才用 | 仅语义理解、确认界面状态、辅助判断目标 | 不可信其坐标 |
Windows 下窗口截图和操作使用 ljqCtrl:严禁 pyautogui;记得先 Activate 到前台;
-坑1-DPI:一律物理坐标;坑2-遮盖/失焦:混乱先枚举窗口确认前台;
+ui_detect附送OCR,不要单独使用OCR
+坑1-DPI:必须先import ljqCtrl,之后一律使用物理坐标;坑2-遮盖/失焦:混乱先枚举窗口确认前台;
ui_detect 的 bbox 是截图内坐标,点击前必须用 `ClientToScreen(hwnd,(0,0))/dpi_scale + bbox中心` 转屏幕物理坐标
坐标转换禁用 `GetWindowRect` 或 DWM 窗口矩形直接加截图坐标(含标题栏/边框/阴影会错位)
ljqCtrl.Click 后会返回像素/前台变化,0% 或近 0% 变化立即停下诊断,禁止盲目重试。
diff --git a/memory/subagent.md b/memory/subagent.md
index 702667e4..ae4b3b03 100644
--- a/memory/subagent.md
+++ b/memory/subagent.md
@@ -1,40 +1,38 @@
# Subagent 调用 SOP
-## 文件IO协议
+## 两种模式
-- 目录:`temp/{task_name}/`(cwd在temp/时即`./{task_name}/`)
-- 启动:`python agentmain.py --task {name} [--input "短文本"] [--llm_no N]`(cwd=代码根)
+### --func 纯函数模式
+- `python agentmain.py --func prompt.txt [--llm_no N]`(cwd=代码根)
+- 读prompt文件→执行→结果写`prompt.out.txt`→退出,主agent读完可删
+- 后台启动(print PID),加`--nobg`前台同步等结果
+- 适用:单次任务、并行map、不需要追问的场景
+
+### --task 持续协作模式
+- `python agentmain.py --task {name} [--input "短文本"] [--llm_no N]`(cwd=代码根)
- `--input`自动建目录+清旧output+写input.txt;长文本先手动写input.txt再启动(不带--input)
-- 自动后台启动,print PID then exit
-- 统一设定:所有agent的cwd都是temp,方便文件共享,不是task目录
-- input:目标+约束即可,subagent同等智能。**禁写步骤/过度描述**,大量数据给路径
-- 通信:output.txt(append,`[ROUND END]`=轮完成) → 写reply.txt继续 → 不写10min退出。reply后输出为output1/2/3.txt(同格式)
+- **不要--nobg**(会卡在等reply循环),只能后台启动
+- 通信:output.txt(`[ROUND END]`=轮完成) → 写reply.txt继续 → 不写10min退出。reply后输出为output1/2/3.txt
- 干预文件:`_stop`(当轮结束) | `_keyinfo`(注入working memory) | `_intervene`(追加指令)
-- [[可选fork功能]](继承对话上下文): 事先code_run(inline_eval=True),将变量history(自动注入,str)写入task目录下_history.json
-- [[可选监察者模式]]:**主agent空闲时应读output观察进度,必要时用干预文件纠偏,禁止无脑长时间sleep**
- 若加`--verbose`,output将包含工具执行结果,主agent可直接审查原始数据而非仅信任摘要
+- [[可选fork]]:将变量history(str)写入task目录下`_history.json`继承对话上下文
+- [[可选监察者]]:主agent空闲时读output观察进度,必要时干预文件纠偏。加`--verbose`可审查原始数据
+
+## 共通规则
+- 所有agent的cwd=temp,方便文件共享
+- input:目标+约束即可,subagent同等智能。**禁写步骤/过度描述**,大量数据给路径
## 场景1:测试模式 - 行为验证
**用途**:观察agent真实行为,修正RULES/L2/L3/SOP
-**流程**:创建test_path/写input.txt→启动subagent→轮询output.txt(2秒间隔)→验证→清理重复
-**测试原则**:只给目标,不提示位置/不诱导做法,观察自主选择
-**修正闭环**:发现问题→设计测试→定位根源(RULES/L2/L3/SOP)→patch修正→验证
-**技术要点**:Insight优先级>SOP;subagent的cwd=temp/
+**流程**:写prompt→启动subagent→轮询结果→验证→清理
+**原则**:只给目标,不提示位置/不诱导做法;Insight优先级>SOP;subagent的cwd=temp/
**两种测试**:
-- 测SOP质量:input指定SOP名(如"用ezgmail_sop查看最近3封未读邮件"),排除导航干扰,失败即SOP问题
-- 测导航能力:input只写目标,验证subagent能自主从insight找到正确SOP。禁止内联SOP内容
+- 测SOP质量:input指定SOP名,排除导航干扰,失败即SOP问题
+- 测导航能力:input只写目标,验证能自主从insight找到正确SOP
## 场景2:Map模式 - 并行处理
-**用途**:将N个独立同构子任务分发给各自的subagent处理
-**核心优势**:独立上下文。避免处理文档A的长上下文污染处理文档B的质量
-**约束**:
-- 文件系统共享是优点:不同agent处理不同输入文件,产生不同输出文件
-- 共享资源冲突:键鼠不可共享;浏览器避免操作同一tab
-- 不满足map模式的任务 → 主agent顺序执行即可,别用subagent
-**标准流程(map-reduce)**:
-1. 主agent准备阶段:爬取/dump数据,存为多个独立输入文件
-2. 分发:对每个文件启动一个subagent处理(主agent自己也可以处理其中一个)
-3. 收集:等所有subagent完成,主agent读取各输出文件,汇总结果
+**用途**:N个独立同构子任务分发,独立上下文避免交叉污染
+**约束**:文件系统共享(优点);键鼠不可共享;浏览器避免同tab
+**流程**:准备独立输入文件→每个启动subagent(--func优先)→收集输出汇总
## subagent内部plan_mode使用
**原则**:subagent本身是完整agent,接收多步骤任务时应在内部创建plan管理执行