diff --git a/agent_loop.py b/agent_loop.py
index 26cbebe..70344aa 100644
--- a/agent_loop.py
+++ b/agent_loop.py
@@ -69,6 +69,7 @@ def agent_runner_loop(client, system_prompt, user_input, handler, tools_schema,
showarg = get_pretty_json(args)
if not verbose and len(showarg) > 200: showarg = showarg[:200] + ' ...'
yield f"🛠️ **正在调用工具:** `{tool_name}` 📥**参数:**\n````text\n{showarg}\n````\n"
+ handler.current_turn = turn + 1
gen = handler.dispatch(tool_name, args, response)
if verbose:
yield '`````\n'
diff --git a/assets/tools_schema.json b/assets/tools_schema.json
index 95149da..7e8f703 100644
--- a/assets/tools_schema.json
+++ b/assets/tools_schema.json
@@ -43,7 +43,7 @@
"name": "web_execute_js",
"description": "万能网页操控工具。通过执行 JavaScript 脚本实现对浏览器的完全控制(如点击、滚动、提取特定数据)。鼓励在有把握情况下(记忆中有selector/做法等)精准使用以减少web_scan调用。执行结果可选择保存到本地文件进行后续分析。",
"parameters": {"type": "object", "properties": {
- "script": {"type": "string", "description": "要执行的 JavaScript 代码。"},
+ "script": {"type": "string", "description": "要执行的 JavaScript 代码或JS文件路径。"},
"save_to_file": {"type": "string", "description": "可选。将 JS 执行结果(js_return)保存到的文件路径。该功能不支持 await 等异步结果。"}}, "required": ["script"]}
}},
{"type": "function", "function": {
@@ -62,7 +62,7 @@
}},
{"type": "function", "function": {
"name": "start_long_term_update",
- "description": "准备开始提炼记忆。发现值得长期记忆的信息(环境事实/用户偏好/避坑经验)时调用此工具。一次用户对话只允许调用一次,已记忆更新或在自主流程内时无需调用。",
+ "description": "准备开始提炼记忆。发现值得长期记忆的信息(环境事实/用户偏好/避坑经验)时调用此工具。已记忆更新或在自主流程内时无需调用。超15轮完成的任务必须调用以沉淀经验。",
"parameters": {"type": "object", "properties": {}}}
}
]
\ No newline at end of file
diff --git a/ga.py b/ga.py
index ce08b32..0b50232 100644
--- a/ga.py
+++ b/ga.py
@@ -247,7 +247,7 @@ class GenericAgentHandler(BaseHandler):
self.parent = parent
self.key_info = ""
self.related_sop = ""
- self.cwd = cwd
+ self.cwd = cwd; self.current_turn = 0
self.history_info = last_history if last_history else []
self.code_stop_signal = []
@@ -313,6 +313,9 @@ class GenericAgentHandler(BaseHandler):
'''
script = args.get("script", "")
if not script: return StepOutcome(None, next_prompt="[Error] Empty script param. Check your tool call arguments.")
+ abs_path = self._get_abs_path(script.strip())
+ if os.path.isfile(abs_path):
+ with open(abs_path, 'r', encoding='utf-8') as f: script = f.read()
save_to_file = args.get("save_to_file", "")
switch_tab_id = args.get("switch_tab_id") or args.get("tab_id")
result = web_execute_js(script, switch_tab_id=switch_tab_id)
@@ -471,6 +474,7 @@ class GenericAgentHandler(BaseHandler):
def _get_anchor_prompt(self):
h_str = "\n".join(self.history_info[-20:])
prompt = f"\n### [WORKING MEMORY]\n\n{h_str}\n"
+ prompt += f"\nCurrent turn: {self.current_turn}\n"
if self.key_info: prompt += f"\n{self.key_info}"
if self.related_sop: prompt += f"\n有不清晰的地方请再次读取{self.related_sop}"
try: print(prompt)
diff --git a/memory/memory_management_sop.md b/memory/memory_management_sop.md
index 9a48271..3621524 100644
--- a/memory/memory_management_sop.md
+++ b/memory/memory_management_sop.md
@@ -10,6 +10,8 @@
3. **禁止存储易变状态 (No Volatile State)**
* **定义**:严禁存储随时间/会话高频变化的数据。
* **示例**:当前时间戳、临时 Session ID、正在运行的 PID、某个具体绝对路径、连接的设备信息
+4. **最小充分指针 (Minimum Sufficient Pointer)**
+ * 上层只留能定位下层的最短标识,多一词即冗余。
---
## 记忆层级架构
```
@@ -24,7 +26,7 @@ L3: ../memory/ (记录库层 - 包含 .md/.py 等各类文件)
### L1:全局内存索引 (global_mem_insight.txt)
**职责**:为 L2 和 L3 提供极简导航索引,确保关键能力可被发现。
**特征**:
-- 体积限制:≤ 30 行(硬约束)
+- 体积限制:≤ 30 行(硬约束),严禁填写细节(除非极高频任务)
- 内容:两层「场景关键词→记忆定位」映射 + RULES(红线规则 + 高频犯错点)
- 第一层:高频场景 key→value(直接给出 sop/py/L2 section 名),自包含可只写一个词
- 第二层:低频场景仅列关键词,需要时 read L2 或 ls L3 自行定位
@@ -41,7 +43,7 @@ L3: ../memory/ (记录库层 - 包含 .md/.py 等各类文件)
**特征**:
- 趋势:随环境扩展而膨胀(可接受)
- 内容:按 `## [SECTION]` 组织的事实条目
-- 同步:变化时更新 L1 的相应 TOPIC 导航行
+- 同步:变化时更新 L1 的相应 TOPIC 导航行,只能导航
**禁止**:禁止存储易变状态、禁止存储猜测、严禁存储大模型可推理的通用常识
---
### L3:任务级精简记录库 (../memory/)
@@ -61,6 +63,9 @@ L3: ../memory/ (记录库层 - 包含 .md/.py 等各类文件)
| L2/L3 删除场景 | 删除对应层的关键词/映射行 |
| L2/L3 修改值 | 若不影响场景定位则不动 L1 |
| 发现通用避坑规律 | 压缩为一句加入 RULES |
+
+> **同步红线**:L1 只写关键词/名称,禁搬细节。
+
---
## 信息分类快速决策树
```
diff --git a/sidercall.py b/sidercall.py
index 0a6a87a..9f99a8b 100644
--- a/sidercall.py
+++ b/sidercall.py
@@ -101,6 +101,7 @@ class LLMSession:
def _endpoint(self, path):
if self.api_base.endswith('/v1'): return f"{self.api_base}/{path.lstrip('/')}"
+ if self.api_base.endswith('$'): return f"{self.api_base.rstrip('$')}/{path.lstrip('/')}"
return f"{self.api_base}/v1/{path.lstrip('/')}"
def _retry_delay(self, resp, attempt):
@@ -211,9 +212,7 @@ class LLMSession:
try: body = (resp.text or "").strip()
except: body = ""
body = body[:1200] if body else ""
- rid = ""
- retry_after = ""
- ct = ""
+ rid = ""; retry_after = ""; ct = ""
try:
h = resp.headers or {}
rid = h.get("x-request-id") or h.get("request-id") or ""