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 ""