diff --git a/README.md b/README.md index 4eb5a2c..0aa0d1e 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,14 @@ cp mykey_template.py mykey.py python launch.pyw ``` +**Also runs on Android** — tested successfully on Termux with `python agentmain.py` (CLI frontend): + +```bash +# In Termux +cd /sdcard/ga +python agentmain.py +``` + Once running, tell the agent: *"Execute web setup SOP to unlock browser tools"* — it handles the rest. See [WELCOME_NEW_USER.md](WELCOME_NEW_USER.md) for the full bootstrap sequence. ## vs. Alternatives @@ -193,6 +201,14 @@ cp mykey_template.py mykey.py python launch.pyw ``` +**同样可在 Android 上运行** — 已在 Termux 上测试通过,通过 `python agentmain.py`(CLI 前端)启动: + +```bash +# 在 Termux 中 +cd /sdcard/ga +python agentmain.py +``` + 启动后告诉 Agent:"执行 web setup SOP 解锁浏览器工具"——剩下的它自己搞定。完整引导流程见 [WELCOME_NEW_USER.md](WELCOME_NEW_USER.md)。 ## 对比 diff --git a/agentmain.py b/agentmain.py index 7cf07bd..6a3d3ef 100644 --- a/agentmain.py +++ b/agentmain.py @@ -80,7 +80,8 @@ class GeneraticAgent: handler = GenericAgentHandler(None, self.history, './temp') if self.handler and self.handler.key_info: handler.key_info = self.handler.key_info - handler.key_info += '\n如你确信任务已经改变,请先更新工作记忆去除无用部分\n' + if '如你确信任务已经改变' not in handler.key_info: + handler.key_info += '\n如你确信任务已经改变,请先更新工作记忆去除无用部分\n' self.handler = handler self.llmclient.backend = self.llmclient.backends[self.llm_no] gen = agent_runner_loop(self.llmclient, sys_prompt, raw_query, @@ -93,8 +94,9 @@ class GeneraticAgent: if len(full_resp) - last_pos > 50: display_queue.put({'next': full_resp[last_pos:] if self.inc_out else full_resp, 'source': source}) last_pos = len(full_resp) + if self.inc_out and last_pos < len(full_resp): display_queue.put({'next': full_resp[last_pos:], 'source': source}) 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) + 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}) self.history = handler.history_info except Exception as e: @@ -139,21 +141,25 @@ if __name__ == '__main__': open('./temp/scheduler.log', 'a', encoding='utf-8').write(f'[{datetime.now():%m-%d %H:%M}] {tag}\n{item["done"]}\n\n') while True: now = datetime.now() - for f in os.listdir('./tasks/pending'): + for f in os.listdir('./sche_tasks/pending'): m = re.match(r'(\d{4}-\d{2}-\d{2})_(\d{4})_', f) if m and now >= datetime.strptime(f'{m[1]} {m[2]}', '%Y-%m-%d %H%M'): - raw = open(f'./tasks/pending/{f}', encoding='utf-8').read() - dq = agent.put_task(f'按scheduled_task_sop执行任务文件 ../tasks/pending/{f}(立刻移到running)\n内容:\n{raw}', source='scheduler') + raw = open(f'./sche_tasks/pending/{f}', encoding='utf-8').read() + dq = agent.put_task(f'按scheduled_task_sop执行任务文件 ../sche_tasks/pending/{f}(立刻移到running)\n内容:\n{raw}', source='scheduler') threading.Thread(target=drain, args=(dq, f), daemon=True).start() break time.sleep(55 + random.random() * 10) else: agent.inc_out = True while True: - q = input('> ').strip() - if not q: continue - dq = agent.put_task(q, source='user') - while True: - item = dq.get() - if 'next' in item: print(item['next'], end='', flush=True) - if 'done' in item: print(); break \ No newline at end of file + try: + q = input('> ').strip() + if not q: continue + dq = agent.put_task(q, source='user') + while True: + item = dq.get() + if 'next' in item: print(item['next'], end='', flush=True) + if 'done' in item: print(); break + except KeyboardInterrupt: + agent.abort() + print('\n[Interrupted]') \ No newline at end of file diff --git a/assets/insight_fixed_structure.txt b/assets/insight_fixed_structure.txt index 8e9b47c..f2efc13 100644 --- a/assets/insight_fixed_structure.txt +++ b/assets/insight_fixed_structure.txt @@ -6,4 +6,4 @@ Insight是索引,L2/L3变更时同步Insight。写记忆前先读META-SOP(L0) 2. 决策前查记忆库;未查证不断言。 3. 分步执行逐步验证;3次失败请求干预。 4. 密钥文件仅引用,不读取/移动。 -5. 写任何记忆前读META-SOP核验。 +5. 写任何记忆前读META-SOP核验,memory下文件只能patch修改(除非新建)。 diff --git a/memory/adb_ui.py b/memory/adb_ui.py index fd83dbb..b2a5fc1 100644 --- a/memory/adb_ui.py +++ b/memory/adb_ui.py @@ -13,8 +13,7 @@ def _dump_u2(): import uiautomator2 as u2 d = u2.connect() xml_str = d.dump_hierarchy() - if xml_str and len(xml_str) > 100: - return xml_str + if xml_str and len(xml_str) > 100: return xml_str except Exception as e: print(f"[u2 fallback] {e}") return None @@ -24,9 +23,7 @@ def _dump_native(): subprocess.run([ADB, "shell", "rm", "-f", "/sdcard/ui.xml"], capture_output=True) r = subprocess.run([ADB, "shell", "uiautomator", "dump", "--compressed", "/sdcard/ui.xml"], capture_output=True, text=True, timeout=15) - if "dumped" not in r.stdout.lower() and "dumped" not in r.stderr.lower(): - print(f"dump failed: {r.stdout}{r.stderr}") - return None + if "dumped" not in r.stdout.lower() and "dumped" not in r.stderr.lower(): print(f"dump failed: {r.stdout}{r.stderr}"); return None subprocess.run([ADB, "pull", "/sdcard/ui.xml", LOCAL_XML], capture_output=True, timeout=10) with open(LOCAL_XML, "r", encoding="utf-8") as f: return f.read() @@ -36,6 +33,8 @@ def _parse_xml(xml_str, keyword=None, clickable_only=False, raw=False): root = ET.fromstring(xml_str) nodes = [] for n in root.iter("node"): + pkg = n.get("package", "") + if "termux" in pkg.lower(): continue text = n.get("text", "") desc = n.get("content-desc", "") bounds = n.get("bounds", "") @@ -43,20 +42,17 @@ def _parse_xml(xml_str, keyword=None, clickable_only=False, raw=False): cls = n.get("class", "").split(".")[-1] rid = n.get("resource-id", "") label = text or desc - if not label and not raw: - continue - if clickable_only and not click: - continue - if keyword and keyword.lower() not in (label or "").lower(): - continue + if not label and not raw: continue + if clickable_only and not click: continue + if keyword and keyword.lower() not in label.lower(): continue cx, cy = 0, 0 if bounds: m = re.findall(r'\[(\d+),(\d+)\]', bounds) if len(m) == 2: cx = (int(m[0][0]) + int(m[1][0])) // 2 cy = (int(m[0][1]) + int(m[1][1])) // 2 - nodes.append({"label": label, "click": click, "bounds": bounds, - "cx": cx, "cy": cy, "class": cls, "id": rid}) + nodes.append({"text": text or desc, "click": click, + "bounds": bounds, "cx": cx, "cy": cy, "class": cls, "id": rid}) return nodes def ui(keyword=None, clickable_only=False, raw=False): @@ -66,15 +62,13 @@ def ui(keyword=None, clickable_only=False, raw=False): raw: 返回原始节点列表而非打印 """ xml_str = _dump_u2() or _dump_native() - if not xml_str: - print("dump failed (both u2 and native)") - return [] + if not xml_str: print("dump failed (both u2 and native)"); return [] nodes = _parse_xml(xml_str, keyword, clickable_only, raw) if not raw: for n in nodes: flag = "Y" if n["click"] else " " coord = f"({n['cx']},{n['cy']})" if n['cx'] else "" - print(f"[{flag}] {n['label']} {coord} {n['bounds']}") + print(f"[{flag}] {n['text']} {coord} {n['bounds']}") print(f"\ntotal: {len(nodes)} nodes") return nodes diff --git a/memory/autonomous_operation_sop.md b/memory/autonomous_operation_sop.md index c7261d8..1b17f23 100644 --- a/memory/autonomous_operation_sop.md +++ b/memory/autonomous_operation_sop.md @@ -3,7 +3,7 @@ 授权你进行自主行动,只要不对环境造成副作用都可进行。 请先选择核心目标,再选择一个小目标进行。最终探测结果形成报告(含操作申请),待用户回来确认后再进行可能的写入或修改操作。 -> **启动时写入工作记忆**:`自主探索|≤15回合|只有cwd内可写|用户不在(问题存报告)|收尾:更新history.txt+重读本SOP检查遗漏|产出=报告+记忆提案` +> **启动时写入工作记忆**:`自主探索|≤15回合|只有cwd内可写|用户不在(问题存报告)|收尾:重读本SOP检查遗漏+更新history|产出=报告+记忆提案` ## 🎯 核心目标(按价值优先级排序) @@ -44,7 +44,8 @@ ### 阶段 1:自主探测(用户离开时) - **启动检查**: - 读取可能有的 `./autonomous_reports/history.txt` 了解历史记录。 - - **不连续选择相同方向**。 + - **TODO优先**:若cwd下存在 `TODO.txt`,优先从中选择任务执行;任务完成后从TODO.txt中移除对应条目。 + - **不连续选择相同方向**(TODO任务除外)。 - **预期收益声明**:选定任务后,必须先用一句话写明「做这个任务预期带来什么收益」。允许探索失败,但必须事先想清楚为什么值得做。这句话写入报告开头。 - **执行方式**:基于目标自由进行,无需预先批准,直接执行只读或实验性操作。 - **约束**:小步快跑,每次只做一个小任务(剩下的下次再做),控制在15个回合以内。严禁修改核心记忆/系统设置;严禁读取敏感数据(但可以检测存在性)。 diff --git a/memory/scheduled_task_sop.md b/memory/scheduled_task_sop.md index d2f7526..a2396cc 100644 --- a/memory/scheduled_task_sop.md +++ b/memory/scheduled_task_sop.md @@ -1,13 +1,13 @@ # 定时任务 SOP -目录:`../tasks/{pending,running,done}/` +目录:`../sche_tasks/{pending,running,done}/` 文件名:`YYYY-MM-DD_HHMM_描述.md`,内容含prompt和schedule ## 流程 -1. [AUTO]唤醒 → `datetime.now()`取当前时间,`ls ../tasks/pending/`,文件名时间≤当前→到期,选择一个 +1. [AUTO]唤醒 → `datetime.now()`取当前时间,`ls ../sche_tasks/pending/`,文件名时间≤当前→到期,选择一个 2. **立即rename到running/**(先占再读,防多进程重复领) 3. 读文件执行 4. 完成→移到done/,**在文件内追加执行报告**供用户查阅 5. schedule非once→算下次时间,新建文件到pending/ -注意tasks目录在../,即你的code root下 +注意sche_tasks目录在../,即你的code root下 diff --git a/memory/tmwebdriver_sop.md b/memory/tmwebdriver_sop.md index b90aa94..5e24fac 100644 --- a/memory/tmwebdriver_sop.md +++ b/memory/tmwebdriver_sop.md @@ -40,3 +40,17 @@ - "访问"链接:遍历所有`a`找`textContent.includes('访问')`的href - 缩略图base64:结果中`img[src^="data:image"]`可直接提取保存 - 下载大图时注意JS返回的src可能被截断,用`return img.src`获取完整URL + +## Chrome下载PDF(fetch+blob方案) +- 场景:页面上的PDF链接点击后会在浏览器内预览而非下载 +- 方案:用JS `fetch(url)` 获取blob → `URL.createObjectURL(blob)` → 创建隐藏``标签设`download`属性 → 触发click → 自动下载到~/Downloads +- 模板: + ```js + fetch('PDF_URL').then(r=>r.blob()).then(b=>{ + const a=document.createElement('a'); + a.href=URL.createObjectURL(b); + a.download='filename.pdf'; + a.click(); + }); + ``` +- 注意:需同源或CORS允许;跨域时可能需要先导航到目标域再执行 diff --git a/sche_tasks/done/2026-02-15_0800_检查未读邮件_已读.md b/sche_tasks/done/2026-02-15_0800_检查未读邮件_已读.md new file mode 100644 index 0000000..7e9b7d1 --- /dev/null +++ b/sche_tasks/done/2026-02-15_0800_检查未读邮件_已读.md @@ -0,0 +1,36 @@ +schedule: daily 0800 +prompt: 按ezgmail_sop读取所有未读邮件,判断是否有重要信息(紧急/截止日期/需回复的),将摘要写入执行报告。全部设为已读。 + +--- +执行时间: 2026-02-15 08:01:23 + + +--- +## 执行报告 + +## 未读邮件检查报告 + +**检查时间**: 2026-02-15 08:02:11 +**未读邮件总数**: 3 + +### 重要邮件 (2封) + +- **624215 是你的 X 验证码** + 发件人: X + 日期: Sat, 14 Feb 2026 16:34:06 +0000 + 备注: X平台验证码(624215),如正在登录请使用 + +- **CACTER邮件安全海外接收隔离区邮件通知目录摘要/CACTER Safe overseas reception quarantine email notification abstract** + 发件人: emailgateway@cacter.com + 日期: Fri, 13 Feb 2026 18:06:12 +0800 (CST) + 备注: 邮件安全隔离区通知,可能有邮件被隔离 + +### 普通邮件 (1封) + +- COLLABORATION OPPORTUNITY FOR RELIABLE SUPPLY OF PHARMACEUTICAL RAW MATERIALS. + 发件人: Karen Lucille Hale + 备注: 可疑商业合作邮件,疑似垃圾邮件 + + +**执行状态**: 成功 +**完成时间**: 2026-02-15 08:02:24 diff --git a/sche_tasks/done/2026-02-16_0800_检查未读邮件_已读.md b/sche_tasks/done/2026-02-16_0800_检查未读邮件_已读.md new file mode 100644 index 0000000..36fc9ed --- /dev/null +++ b/sche_tasks/done/2026-02-16_0800_检查未读邮件_已读.md @@ -0,0 +1,33 @@ +schedule: daily 0800 +prompt: 按ezgmail_sop读取所有未读邮件,判断是否有重要信息(紧急/截止日期/需回复的),将摘要写入执行报告。全部设为已读。 + + +--- + +# 邮件检查报告 - 2026-02-16 08:01 + +## 摘要 +- 总计未读邮件:2 封 +- 重要邮件:1 封 +- 普通邮件:1 封 + +## 重要邮件详情 + +### 1. ARR January 2026 会议通知 +- **发件人**: ARR - January 2026 +- **主题**: [ARR January] Author-reviewer discussion phase starts now +- **日期**: 2026-02-15 23:40 +- **重要性**: 高 - 有时间限制 +- **说明**: 学术会议作者-审稿人讨论阶段已开始,需要及时查看审稿意见并准备回复 +- **建议**: 尽快登录 OpenReview 查看审稿意见并准备回复 + +## 普通邮件 + +### 1. Academia.edu 引用通知 +- **发件人**: Academia Mentions +- **主题**: Are you the "JiaQing Liang" cited in Artificial Intelligence papers? +- **说明**: 营销邮件,通知有论文引用了相关姓名 + +## 操作记录 +- 所有邮件已标记为已读 +- 执行时间: 2026-02-16 08:01:18 diff --git a/sche_tasks/done/2026-02-17_0800_检查未读邮件_已读.md b/sche_tasks/done/2026-02-17_0800_检查未读邮件_已读.md new file mode 100644 index 0000000..0b59ed7 --- /dev/null +++ b/sche_tasks/done/2026-02-17_0800_检查未读邮件_已读.md @@ -0,0 +1,33 @@ +# 邮件检查执行报告 + +**执行时间**: 2026-02-17 08:01:14 +**任务**: 检查未读邮件 + +## 摘要 +- 共检查 3 封未读邮件 +- 重要邮件: 0 封 +- 所有邮件已标记为已读 + +## 邮件详情 + +### [1] 普通 +- **发件人**: do-not-reply@iclr.cc +- **主题**: ICLR 2026 Update Poster Presentation Details +- **日期**: Mon, 16 Feb 2026 22:47:44 +0000 (UTC) + +### [2] 普通 +- **发件人**: ARR - January 2026 +- **主题**: [ARR - January 2026] An author commented on your submission. Paper Number: 4724, Paper Title: "CultureScope: A Dimensional Lens for Probing Cultural Understanding in LLMs" +- **日期**: Mon, 16 Feb 2026 15:02:09 +0000 (UTC) + +### [3] 普通 +- **发件人**: ARR - January 2026 +- **主题**: [ARR - January 2026] An author commented on your submission. Paper Number: 4724, Paper Title: "CultureScope: A Dimensional Lens for Probing Cultural Understanding in LLMs" +- **日期**: Mon, 16 Feb 2026 14:43:11 +0000 (UTC) + +## 结论 +本次检查未发现需要紧急处理的邮件。 +- ICLR 2026 会议通知:海报展示细节更新 +- ARR论文评审:作者评论通知(2封) + +所有邮件已标记为已读。 diff --git a/sche_tasks/done/2026-02-18_0800_检查未读邮件_report.md b/sche_tasks/done/2026-02-18_0800_检查未读邮件_report.md new file mode 100644 index 0000000..33e1d05 --- /dev/null +++ b/sche_tasks/done/2026-02-18_0800_检查未读邮件_report.md @@ -0,0 +1,82 @@ +# 邮件检查执行报告 + +**执行时间**: 2026-02-18 08:00:54 +**任务**: 检查未读邮件 (daily 0800) + +## 执行结果 + +- **总未读邮件数**: 13 封 +- **重要邮件数**: 8 封 +- **处理状态**: 所有邮件已标记为已读 ✓ + +## 重要邮件摘要 + +### 1. [ARR - January 2026] Official Review posted to your assigned Paper number: 2021, Paper title: "Sparse-RL: Breaking the Memory Wall in LLM Reinforcement Learning via Stable Sparse Rollouts" + +- **发件人**: ARR - January 2026 +- **日期**: Tue, 17 Feb 2026 23:45:24 +0000 (UTC) +- **摘要**: 'A submission to ARR - January 2026, for which you are an official area chair, has received a re + +### 2. [ARR January/ACL 2026] pending review for submission 5119 please reply! + +- **发件人**: acl2026 +- **日期**: Tue, 17 Feb 2026 22:09:57 +0000 +- **摘要**: Dear Jiaqing and Nanyun You are the AC and SAC for paper 5119, which still has a missing review. The + +### 3. [ARR January/ACL 2026] pending review for submission 4966 please reply! + +- **发件人**: acl2026 +- **日期**: Tue, 17 Feb 2026 22:04:02 +0000 +- **摘要**: Dear Jiaqing and Nanyun You are the AC and SAC for paper 4966, which still has a missing review. The + +### 4. [ICML 2026] clarification regarding emergency reviewing + +- **发件人**: OpenReview +- **日期**: Tue, 17 Feb 2026 21:40:32 +0000 (UTC) +- **摘要**: Dear Jiaqing Liang, Thanks again for agreeing to act as an emergency reviewer for ICML during the pe + +### 5. [ARR - January 2026] An author commented on your submission. Paper Number: 215, Paper Title: "What Makes an Ideal Quote? Recommending “Unexpected yet Rational” Quotations via Novelty" + +- **发件人**: ARR - January 2026 +- **日期**: Tue, 17 Feb 2026 09:29:39 +0000 (UTC) +- **摘要**: An author commented on your submission. Paper number: 215 Paper title: What Makes an Ideal Quote? Re + +### 6. [ARR - January 2026] An author commented on your submission. Paper Number: 215, Paper Title: "What Makes an Ideal Quote? Recommending “Unexpected yet Rational” Quotations via Novelty" + +- **发件人**: ARR - January 2026 +- **日期**: Tue, 17 Feb 2026 09:28:56 +0000 (UTC) +- **摘要**: An author commented on your submission. Paper number: 215 Paper title: What Makes an Ideal Quote? Re + +### 7. [ARR - January 2026] An author commented on your submission. Paper Number: 215, Paper Title: "What Makes an Ideal Quote? Recommending “Unexpected yet Rational” Quotations via Novelty" + +- **发件人**: ARR - January 2026 +- **日期**: Tue, 17 Feb 2026 09:26:03 +0000 (UTC) +- **摘要**: An author commented on your submission. Paper number: 215 Paper title: What Makes an Ideal Quote? Re + +### 8. [ARR - January 2026] An author commented on your submission. Paper Number: 215, Paper Title: "What Makes an Ideal Quote? Recommending “Unexpected yet Rational” Quotations via Novelty" + +- **发件人**: ARR - January 2026 +- **日期**: Tue, 17 Feb 2026 09:23:23 +0000 (UTC) +- **摘要**: An author commented on your submission. Paper number: 215 Paper title: What Makes an Ideal Quote? Re + +## 重要信息分析 + +本次检查发现以下需要关注的邮件: + +1. **ARR/ACL 2026 审稿相关** (5封) + - Paper 2021 收到新的 Official Review + - Paper 5119 和 4966 有 pending review 需要回复 + - Paper 215 收到4条作者评论 + +2. **ICML 2026 紧急审稿** (1封) + - 关于 emergency reviewing 的说明 + +**建议行动**: +- 优先处理 Paper 5119 和 4966 的 pending review 回复请求 +- 查看 Paper 215 的作者评论并回复 +- 查看 Paper 2021 的新 review + +## 执行状态 + +✓ 任务执行成功 +✓ 所有未读邮件已标记为已读 diff --git a/sche_tasks/pending/2026-02-19_0800_检查未读邮件.md b/sche_tasks/pending/2026-02-19_0800_检查未读邮件.md new file mode 100644 index 0000000..fd6c24d --- /dev/null +++ b/sche_tasks/pending/2026-02-19_0800_检查未读邮件.md @@ -0,0 +1,2 @@ +schedule: daily 0800 +prompt: 按ezgmail_sop读取所有未读邮件,判断是否有重要信息(紧急/截止日期/需回复的),将摘要写入执行报告。全部设为已读。