feat(file_read): fuzzy file suggestion on not-found with history dirs; sync L1 template
This commit is contained in:
@@ -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 公开版本发布
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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
25
ga.py
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user