feat(file_read): fuzzy file suggestion on not-found with history dirs; sync L1 template

This commit is contained in:
Liang Jiaqing
2026-04-15 20:58:29 +08:00
parent da8bba99a5
commit bd9e45f761
3 changed files with 38 additions and 23 deletions

View File

@@ -60,7 +60,7 @@ After a few weeks, your agent instance will have a skill tree no one else in the
- **2026-03-10:** [Released million-scale Skill Library](https://mp.weixin.qq.com/s/q2gQ7YvWoiAcwxzaiwpuiQ?scene=1&click_id=7)
- **2026-03-08:** [Released "Dintal Claw" — a GenericAgent-powered government affairs bot](https://mp.weixin.qq.com/s/eiEhwo-j6S-WpLxgBnNxBg)
- **2026-03-01:** [GenericAgent featured by Jiqizhixin (机器之心)](https://mp.weixin.qq.com/s/uVWpTTF5I1yzAENV_qm7yg)
- **2026-01-11:** GenericAgent V1.0 public release
- **2026-01-16:** GenericAgent V1.0 public release
---
@@ -251,7 +251,7 @@ MIT License — see [LICENSE](LICENSE)
- **2026-03-10:** [发布百万级 Skill 库](https://mp.weixin.qq.com/s/q2gQ7YvWoiAcwxzaiwpuiQ?scene=1&click_id=7)
- **2026-03-08:** [发布以 GenericAgent 为核心的"政务龙虾" Dintal Claw](https://mp.weixin.qq.com/s/eiEhwo-j6S-WpLxgBnNxBg)
- **2026-03-01:** [GenericAgent 被机器之心报道](https://mp.weixin.qq.com/s/uVWpTTF5I1yzAENV_qm7yg)
- **2026-01-11:** GenericAgent V1.0 公开版本发布
- **2026-01-16:** GenericAgent V1.0 公开版本发布
---

View File

@@ -1,24 +1,22 @@
# [Global Memory Insight]
浏览器自动化: web_scan/web_execute_js直接调用 | 特殊:tmwebdriver_sop(文件上传/图搜/PDF blob/元素物理坐标/Cookie提取含HttpOnly/跨域iframe操控/CDP/跨tab/后台tab操作)
键鼠模拟: ljqCtrl_sop+.py(仅win禁pyautogui/先activate窗口)
定时任务: scheduled_task_sop(报告→sche_tasks/done/) | 与自主任务完全独立
自主探索任务: autonomous_operation_sop(报告→temp/autonomous_reports/history.txt不在memory下) | 与定时任务完全独立
手机操控: adb_ui.py
浏览器特殊操作: tmwebdriver_sop(文件上传/图搜/PDF blob/物理坐标/HttpOnly Cookie/autofill突破/跨域iframe/CDP/跨tab)
键鼠: ljqCtrl_sop(禁pyautogui/先activate) 截图/视觉: ocr/vision_sop | 禁全屏截图,优先窗口
定时:scheduled_task_sop | 自主:autonomous_operation_sop | watchdog/反射:agentmain --reflect
手机:adb_ui.py
需要时read L2 或 ls ../memory/ 查L3
L0(META-SOP): memory_management_sop
L2: 现空
L3: web_setup_sop | autonomous_operation_sop | scheduled_task_sop | ljqCtrl_sop+.py | tmwebdriver_sop | subagent_sop | plan_sop | procmem_scanner.py | adb_ui.py
L4: ../memory/L4_raw_sessions/
L3: memory_cleanup_sop(记忆整理) | skill_search | ui_detect.py | ocr_utils.py | subagent | web_setup_sop | plan_sop
| procmem_scanner | keychain | ljqCtrl_sop+.py | tmwebdriver_sop | autonomous_operation_sop | scheduled_task_sop | vision_sop | adb_ui.py
L4: L4_raw_sessions/
[RULES]
1. 搜索先行: 信息尽量用google必须web, 项目内os.listdir, 禁猜路径
2. 交叉验证: 禁信搜索摘要, 数值进详情页核实
3. 编码安全: 改前必读源码; import memory用sys.path.append
4. 闭环: 物理模拟后确认; 3次失败请求干预;
5. 进程: 禁无条件杀python(杀自己), 精确PID, 禁os.kill判活
6. 窗口: GUI状态优先枚举窗口, 比OCR快
7. 物理红线: cwd用./; cwd指定后代码内禁用../向上切换,改用绝对路径
8. web JS: 一次写对输入用原生setter+事件链点击前检查disabled注意引号转义; scan空再scan或innerText
9. SOP: 执行前读取缓存硬参数,禁凭印象,有utils必用; 复杂长程先读plan_sop
10. 用户提及或复杂长程需规划任务要读plan_sop进入规划模式
1. 搜索先行: 搜文件名严禁不用es(禁PS递归/禁dir遍历), 搜索一定优先使用web工具的google(严禁duckduckgo等), 优先看cwd禁猜路径
2. 交叉验证: 禁信摘要, 数值进详情页核实
3. 编码安全: 禁PS cat/type用file_read; 改前必读; memory模块直接import(已在PATH,禁加虚假前缀)
4. 闭环: 物理模拟后确认; 3次失败请求干预; Git完整闭环
5. 进程: 禁无条件杀python(杀自己), 精确PID, 禁os.kill判活
6. 窗口: GUI状态优先win32gui枚举标题
7. web JS: 输入用原生setter+事件链, 点击前检disabled, 注意引号转义; scan空/不全先稍等再scan, 禁首扫定论
8. SOP: 读SOP禁凭印象,有utils必用 | 复杂长程/用户提及规划→读plan_sop

25
ga.py
View File

@@ -1,7 +1,7 @@
import sys, os, re, json, time, threading, importlib
from datetime import datetime
from pathlib import Path
import tempfile, traceback, subprocess, itertools, collections
import tempfile, traceback, subprocess, itertools, collections, difflib
if sys.stdout is None: sys.stdout = open(os.devnull, "w")
if sys.stderr is None: sys.stderr = open(os.devnull, "w")
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
@@ -221,6 +221,13 @@ def file_patch(path: str, old_content: str, new_content: str):
except Exception as e:
return {"status": "error", "msg": str(e)}
_read_dirs = set()
def _scan_files(base, depth=2):
try:
for e in os.scandir(base):
if e.is_file(): yield (e.name, e.path)
elif depth > 0 and e.is_dir(follow_symlinks=False): yield from _scan_files(e.path, depth - 1)
except (PermissionError, OSError): pass
def file_read(path, start=1, keyword=None, count=200, show_linenos=True):
try:
with open(path, 'r', encoding='utf-8', errors='replace') as f:
@@ -243,7 +250,19 @@ def file_read(path, start=1, keyword=None, count=200, show_linenos=True):
res = [(i, l if len(l) <= L_MAX else l[:L_MAX] + TAG) for i, l in res]
result = "\n".join(f"{i}|{l}" if show_linenos else l for i, l in res)
if show_linenos: result = total_tag + result
_read_dirs.add(os.path.dirname(os.path.abspath(path)))
return result
except FileNotFoundError:
msg = f"Error: File not found: {path}"
try:
tgt = os.path.basename(path); scan = os.path.dirname(os.path.dirname(os.path.abspath(path)))
roots = [scan] + [d for d in _read_dirs if not d.startswith(scan)]
cands = list(itertools.islice((c for base in roots for c in _scan_files(base)), 2000))
top = sorted([(difflib.SequenceMatcher(None, tgt.lower(), c[0].lower()).ratio(), c) for c in cands[:2000]], key=lambda x: -x[0])[:5]
top = [(s, c) for s, c in top if s > 0.3]
if top: msg += "\n\nDid you mean:\n" + "\n".join(f" {c[1]} ({s:.0%})" for s, c in top)
except Exception: pass
return msg
except Exception as e: return f"Error: {str(e)}"
def smart_format(data, max_str_len=100, omit_str=' ... '):
@@ -404,9 +423,7 @@ class GenericAgentHandler(BaseHandler):
show_linenos = args.get("show_linenos", True)
result = file_read(path, start=start, keyword=keyword,
count=count, show_linenos=show_linenos)
if show_linenos:
tips = '由于设置了show_linenos以下返回信息为(行号|)内容 。\n'
result = tips + result
if show_linenos and not result.startswith("Error:"): result = '由于设置了show_linenos以下返回信息为(行号|)内容 。\n' + result
if ' ... [TRUNCATED]' in result: result += '\n\n(某些行被截断,如需完整内容可改用 code_run 读取)'
result = smart_format(result, max_str_len=20000, omit_str='\n\n[omitted long content]\n\n')
next_prompt = self._get_anchor_prompt(skip=args.get('_index', 0) > 0)