rename sidercall.py to llmcore.py; add cache-aware cd to compress_history_tags

This commit is contained in:
Liang Jiaqing
2026-03-13 13:21:32 +08:00
parent 2a98cc44e5
commit fd7bf241d0
7 changed files with 40 additions and 87 deletions

View File

@@ -136,7 +136,7 @@ The agent starts with 7 primitive tools. Through `code_run`, it can install pack
**Core engine** (runs the agent): **Core engine** (runs the agent):
- `agent_loop.py` — Sense-Think-Act loop (92 lines) - `agent_loop.py` — Sense-Think-Act loop (92 lines)
- `ga.py` — Tool definitions and execution - `ga.py` — Tool definitions and execution
- `sidercall.py` — LLM communication (multi-backend) - `llmcore.py` — LLM communication (multi-backend)
- `agentmain.py` — Session orchestration - `agentmain.py` — Session orchestration
**Interface** (talk to the agent): **Interface** (talk to the agent):
@@ -255,7 +255,7 @@ Agent 拥有 7 个原子工具:`code_run`(执行任意代码)、`file_read
**核心引擎** **核心引擎**
- `agent_loop.py` — 感知-思考-行动循环92 行) - `agent_loop.py` — 感知-思考-行动循环92 行)
- `ga.py` — 工具定义与执行 - `ga.py` — 工具定义与执行
- `sidercall.py` — LLM 通信(多后端) - `llmcore.py` — LLM 通信(多后端)
- `agentmain.py` — 会话编排 - `agentmain.py` — 会话编排
**交互界面** **交互界面**

View File

@@ -5,7 +5,7 @@ if sys.stderr is None: sys.stderr = open(os.devnull, "w")
elif hasattr(sys.stderr, 'reconfigure'): sys.stderr.reconfigure(errors='replace') elif hasattr(sys.stderr, 'reconfigure'): sys.stderr.reconfigure(errors='replace')
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from sidercall import SiderLLMSession, LLMSession, ToolClient, ClaudeSession, XaiSession from llmcore import SiderLLMSession, LLMSession, ToolClient, ClaudeSession, XaiSession
from agent_loop import agent_runner_loop, StepOutcome, BaseHandler from agent_loop import agent_runner_loop, StepOutcome, BaseHandler
from ga import GenericAgentHandler, smart_format, get_global_memory, format_error from ga import GenericAgentHandler, smart_format, get_global_memory, format_error
@@ -40,7 +40,7 @@ class GeneraticAgent:
script_dir = os.path.dirname(os.path.abspath(__file__)) script_dir = os.path.dirname(os.path.abspath(__file__))
temp_dir = os.path.join(script_dir, 'temp') temp_dir = os.path.join(script_dir, 'temp')
if not os.path.exists(temp_dir): os.makedirs(temp_dir) if not os.path.exists(temp_dir): os.makedirs(temp_dir)
from sidercall import mykeys from llmcore import mykeys
llm_sessions = [] llm_sessions = []
for k, cfg in mykeys.items(): for k, cfg in mykeys.items():
if not any(x in k for x in ['api', 'config', 'cookie']): continue if not any(x in k for x in ['api', 'config', 'cookie']): continue

View File

@@ -22,7 +22,7 @@
- Python 3.8+ - Python 3.8+
- 本项目完整代码 - 本项目完整代码
- LLM API 密钥Claude/OpenAI 等,已在 `sidercall/mykeys` 中配置) - LLM API 密钥Claude/OpenAI 等,已在 `llmcore/mykeys` 中配置)
### 安装依赖 ### 安装依赖
@@ -177,7 +177,7 @@ fs_allowed_users = [
### 确认 LLM 配置 ### 确认 LLM 配置
确保 `sidercall/mykeys` 中已配置 LLM API 密钥: 确保 `llmcore/mykeys` 中已配置 LLM API 密钥:
```python ```python
# 示例Claude API # 示例Claude API

View File

@@ -5,7 +5,7 @@ from pathlib import Path
import subprocess import subprocess
import tempfile import tempfile
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from sidercall import SiderLLMSession, LLMSession, ToolClient from llmcore import SiderLLMSession, LLMSession, ToolClient
ask = SiderLLMSession().ask ask = SiderLLMSession().ask

View File

@@ -14,8 +14,10 @@ mykeys = _load_mykeys()
proxy = mykeys.get("proxy", 'http://127.0.0.1:2082') proxy = mykeys.get("proxy", 'http://127.0.0.1:2082')
proxies = {"http": proxy, "https": proxy} if proxy else None proxies = {"http": proxy, "https": proxy} if proxy else None
def compress_history_tags(messages, keep_recent=4, max_len=200): def compress_history_tags(messages, keep_recent=10, max_len=500):
"""Compress <thinking>/<tool_use>/<tool_result> tags in older messages to save tokens.""" """Compress <thinking>/<tool_use>/<tool_result> tags in older messages to save tokens."""
compress_history_tags._cd = getattr(compress_history_tags, '_cd', 0) + 1
if compress_history_tags._cd % 5 != 0: return messages
for i, msg in enumerate(messages): for i, msg in enumerate(messages):
if i < len(messages) - keep_recent and 'orig' not in msg: if i < len(messages) - keep_recent and 'orig' not in msg:
msg['orig'] = msg['prompt'] msg['orig'] = msg['prompt']
@@ -47,7 +49,7 @@ class SiderLLMSession:
return full_text return full_text
class ClaudeSession: class ClaudeSession:
def __init__(self, api_key, api_base, model="claude-opus", context_win=10000): def __init__(self, api_key, api_base, model="claude-opus", context_win=12000):
self.api_key, self.api_base, self.default_model, self.context_win = api_key, api_base.rstrip('/'), model, context_win self.api_key, self.api_base, self.default_model, self.context_win = api_key, api_base.rstrip('/'), model, context_win
self.raw_msgs, self.lock = [], threading.Lock() self.raw_msgs, self.lock = [], threading.Lock()
def _trim_messages(self, messages): def _trim_messages(self, messages):
@@ -96,7 +98,7 @@ class ClaudeSession:
return _ask_gen() if stream else ''.join(list(_ask_gen())) return _ask_gen() if stream else ''.join(list(_ask_gen()))
class LLMSession: class LLMSession:
def __init__(self, api_key, api_base, model, context_win=12000, proxy=None, api_mode="chat_completions", def __init__(self, api_key, api_base, model, context_win=16000, proxy=None, api_mode="chat_completions",
max_retries=2, connect_timeout=10, read_timeout=120): max_retries=2, connect_timeout=10, read_timeout=120):
self.api_key = api_key; self.api_base = api_base.rstrip('/'); self.default_model = model self.api_key = api_key; self.api_base = api_base.rstrip('/'); self.default_model = model
self.context_win = context_win; self.raw_msgs = []; self.messages = [] self.context_win = context_win; self.raw_msgs = []; self.messages = []

View File

@@ -1,87 +1,38 @@
# 自主行动 SOP (探测-报告-执行) # 自主行动 SOP
⚠️ **路径警告**autonomous_reports 在 temp/ 下,用`./autonomous_reports/`访问,**不是**`../memory/autonomous_reports/``../autonomous_reports/`
授权你进行自主行动,只要不对环境造成副作用都可进行。
首先根据有无TODO确定**执行模式**或**任务规划模式**
如有TODO进入**执行模式**取一条TODO执行完成后本轮结束不继续执行下一条
如果没有TODO进入**任务规划模式**,深入分析并形成多个有价值的自主探索任务。规划完成后本轮结束,待下次自主行动执行。
⚠️ **路径警告**autonomous_reports 在 temp/ 下,用`./autonomous_reports/`访问,**不是**`../memory/autonomous_reports/``../autonomous_reports/`TODO在cwd下。
报告存于 `./autonomous_reports/`,文件名 `RXX_简短描述.md`XX从 history.txt 推断自增)。 报告存于 `./autonomous_reports/`,文件名 `RXX_简短描述.md`XX从 history.txt 推断自增)。
## 任务规划模式 授权你进行自主行动,只要不对环境造成副作用都可进行。
- **有TODO**cwd下 `TODO.txt` 有待执行条目 → 直接跳到「执行流程」
价值公式:**「AI训练数据无法覆盖」×「对未来协作有持久收益」**。核心产出是记忆——有价值的发现整理为记忆更新提案纳入报告。 ## 任务选择
-`./TODO.txt`temp根目录未完成条目 → 取**一条**,直接进入执行,其他条目下次执行
- 无 TODO → 读 `autonomous_operation_sop/task_planning.md` 规划,下次执行
- 不连续两次选相同子任务
流程入口: 价值公式:**「AI训练数据无法覆盖」×「对未来协作有持久收益」**
- **无TODO → 进入任务规划模式**(本轮不执行任务,专注规划):
0. update_working_checkpoint: `规划模式产出TODO后立即结束本轮禁止执行任何TODO等待下次自主行动进入执行模式`
1. ⚠️ **批判性读history.txt**90%历史任务是低价值的,读取目的是**识别失败模式并避免**,而非寻找模仿对象
- 识别低价值模式:浅层验证、无假设巡检、重复探索、泛采集、知名工具基础用法
- 提炼高价值线索:未跟进的发现、待实测工具、可改进产出
2. 反思:为什么这些任务低价值?如何设计才能高价值?
3. 批判性盘点已有报告和记忆ls autonomous_reports/ + ../memory考虑如何发挥更大价值或优化
4. 综合以上产出5-7条TODO写入 `TODO.txt`TODO已完成内容可压缩丢后面
5. 每条格式:`[ ] 类型(产出/冲浪/环境) | 一句话目标 | 验收标准`
6. 召唤subagent评审TODOinput仅给TODO列表+"读记忆库自行判断逐条评分1-10并简述理由"(不喂额外先验信息)
7. 读subagent评分低分项删除或替换
8. 立刻**结束**,下次行动再执行
目标排序(按价值递减): ## 执行
1. **实用产出与能力扩展**:写工具解决痛点,在已有能力上解锁新能力(能力树每多一个节点,可能性空间变大)
2. **环境发现**:扫描已有但未利用的工具/库/数据源/配置
3. **小众工具挖掘**在GitHub/V2EX/吾爱破解/果核剥壳**等**找冷门实用工具实测AI常推荐但有坑的方案
4. **了解用户与推荐**:分析老代码/PC文件/书签推断偏好,给出个性化推荐(游戏/视频/工具附理由)(低频)
5. **自身演进**:思考框架不足,提出改进方案
6. **记忆审查**:修正错误或过时记录
**大型任务**允许设计**有价值**的大型任务将其分解成若干个模块或步骤写入TODO中每次自主行动执行处理一个模块。 **启动**
- update_working_checkpoint: `自主行动|报告→./autonomous_reports/R{XX}_简短描述.md≤30回合收尾重读sop写报告+更新history+标记TODO`
-`./autonomous_reports/history.txt` 推断下一编号RXX + 了解历史避免重复
选择原则个性化优先只有探测这台PC才能获得的知识→ 盲区优先(自身参数无法复现,有一定难度)→ 假设驱动(明确要验证什么,边探测边实验)→ 禁止低价值验证(不验证静态配置、不做无假设巡检、不做你轻易完成的工作) **执行**
- ≤30回合小步快跑边探测边实验
- 用临时脚本验证假设;禁只读即下结论,完整验证再写报告
- 即使失败也记录实验过程和结果,失败报告同样有价值
- 用户不在线,遇到需要决策的问题写入报告待审,不要卡住
探测策略(聚焦原则,非菜单) **收尾(三件事缺一不可)**
- **线索驱动**:从近期报告中提炼的后续任务,优先于凭空选题 1. 写报告 `./autonomous_reports/R{XX}_简短描述.md`,格式简洁仅关键发现详述;若有记忆更新建议,附在报告末尾
- **能力树扩展**:优先能解锁新能力节点的工具/技能(一个节点带来多种可能性 2. 更新 `./autonomous_reports/history.txt`prepend一条`RXX | 日期 | 类型 | 主题 | 结论`,严格单行,先读此文件头几行了解格式
- **个性化优先**只有探测这台PC/这个用户才能获得的知识 > 通用知识 3.`./TODO.txt`temp根目录中将已完成条目标记为 `[x]`
- 冲浪规则每次≤2话题必须读正文提炼洞察禁标题搬运发现好工具→下轮TODO加实测任务
禁区:❌ Hacker News · 刷新闻头条 · 泛采集标题/无目标刷新闻 · 探索知名工具基础用法 · 调研弱于当前框架的agent · 调研其他web自动化/computer use框架 · 读取自身代码库 ## 权限边界
- 无需批准只读探测、cwd内写操作/脚本实验
- 需写入报告待审:修改 global_mem / memory下SOP、安装软件、外部API调用、删除非临时文件
- 绝对禁止:读取密钥、修改核心代码库、不可逆危险操作
## 等待用户审查
## 执行模式 - 用户归来后审查报告,决定批准、修改或拒绝方案
⚠️ **监工原则(硬约束)**主agent在执行模式中**只当监工**,严禁亲自执行任务的实际工作。
- ❌ 禁止主agent自己写脚本跑数据、调API、扫描目录、处理文件等一切「干活」行为
- ❌ 禁止主agent以「为subagent准备数据」为由自己先执行部分工作
- ✅ 允许选任务、写input.txt任务描述、启动subagent、轮询监控、质检验收、更新history
- 原则:所有实际探测/数据收集/脚本编写/API调用都写进input.txt让subagent去做
### 执行有TODO时
0.`TODO.txt` 取**一条**作为当前任务
1. update_working_checkpoint: `{选定的当前任务}\n自主行动时长期保留subagent任务完成后需重读自主行动sop确定验收流程。每次只执行一个任务`
2. 按 subagent_sop 召唤 subagentinput 需要包含以下全部内容:
- **任务**:详细介绍和要求深入执行当前任务 + 验收标准 + 一句话预期收益
- **所有实际工作都由subagent完成**包括数据收集、目录扫描、API调用、脚本编写等主agent不做任何准备工作
- **权限边界**:可执行只读和实验性操作;严禁修改核心记忆/系统设置严禁读取敏感数据可检测存在性控制在30回合内
- 无需批准只读探测、cwd 内写操作/脚本实验
- 需要报告:修改 global_mem.txt / memory/ 下 SOP、安装软件、外部 API 调用、删除非临时文件
- 绝对禁止:读取密钥、修改核心代码库、不可逆危险操作
- **报告要求**:完成后写报告到 `./autonomous_reports/R{XX}_简短描述.md`XX从history.txt推断格式简洁仅关键发现详述
- 第一步先将此报告要求update_working_checkpoint进入工作记忆
- **行动准则**:边探测边实验,用临时脚本测假设;禁只读即下结论,完整验证再写报告
3. 监控 subagent 执行,质量不佳或跑偏可提前终止放弃(监控≠亲自干活)
### 质检与验收流程
4. subagent 完成后,读取报告进行质检:
- 报告是否符合格式(标题/分类/内容质量)
- 发现不合规可修正报告或回滚操作
- 可通过 reply 机制追问 subagent
5. 更新 `./autonomous_reports/history.txt`prepend先读此文件了解填写格式
- 在 history.txt 首行 prepend 一条:`RXX | 日期 | 类型 | 主题 | 结论`(严格单行)。
6.`TODO.txt` 移除已完成条目
7. 若报告含记忆更新建议,评估后决定是否采纳;若发现极有价值高质量报告,可在报告文件名上标记。
8. 停止,等待下次自主行动
### 等待用户审查
- 用户归来后审查报告,决定批准、修改或拒绝方案

View File

@@ -8,7 +8,7 @@ try:
except: except:
print("Please ask the agent install python-telegram-bot to use telegram module.") print("Please ask the agent install python-telegram-bot to use telegram module.")
sys.exit(1) sys.exit(1)
from sidercall import mykeys from llmcore import mykeys
agent = GeneraticAgent() agent = GeneraticAgent()
agent.verbose = False agent.verbose = False