ga: map Bash/PowerShell tool calls to code_run; conductor: restrict CORS/WS origin & trusted host to localhost; mem SOP: prune stale facts, L2 keeps file pointers

This commit is contained in:
Liang Jiaqing committed 2026-11-02 10:11:21 +08:00
1 parent be17b0adc5
commit 5ec4b12b63
3 files changed
+20 -6

No files matched your search

+1
View File
@@ -16,6 +16,7 @@ def try_call_generator(func, *args, **kwargs):
class BaseHandler: class BaseHandler:
def turn_end_callback(self, response, tool_calls, tool_results, turn, next_prompt, exit_reason): return next_prompt def turn_end_callback(self, response, tool_calls, tool_results, turn, next_prompt, exit_reason): return next_prompt
def dispatch(self, tool_name, args, response, index=0, tool_num=1): def dispatch(self, tool_name, args, response, index=0, tool_num=1):
if tool_name in ('Bash', 'PowerShell'): tool_name, args = 'code_run', {**args, 'type': tool_name.lower(), 'script': args.get('command') or args.get('cmd') or args.get('script') or ''}
method_name = f"do_{tool_name}" method_name = f"do_{tool_name}"
if hasattr(self, method_name): if hasattr(self, method_name):
args['_index'] = index; args['_tool_num'] = tool_num args['_index'] = index; args['_tool_num'] = tool_num
+8 -1
View File
@@ -6,6 +6,7 @@ from contextlib import asynccontextmanager, suppress
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request, HTTPException from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request, HTTPException
from fastapi.responses import FileResponse, PlainTextResponse, JSONResponse from fastapi.responses import FileResponse, PlainTextResponse, JSONResponse
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.trustedhost import TrustedHostMiddleware
from pydantic import BaseModel from pydantic import BaseModel
FRONTENDS_DIR = os.path.dirname(os.path.abspath(__file__)) FRONTENDS_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -133,7 +134,11 @@ async def lifespan(app: FastAPI):
app = FastAPI(title="Conductor", lifespan=lifespan) app = FastAPI(title="Conductor", lifespan=lifespan)
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]) # 只放行本机页面(conductor.html 同源 / 桌面端 Tauri / vite dev),防恶意网页跨站调用
LOCAL_ORIGIN = re.compile(r"^(https?://(127\.0\.0\.1|localhost|\[::1\])(:\d+)?|tauri://localhost|https?://tauri\.localhost)$")
app.add_middleware(CORSMiddleware, allow_origin_regex=LOCAL_ORIGIN.pattern, allow_methods=["*"], allow_headers=["*"])
# 防 DNS rebinding;--key 远程模式或 ::1 监听时不启用
if not args.key and args.host != "::1": app.add_middleware(TrustedHostMiddleware, allowed_hosts=["127.0.0.1", "localhost"])
class RemoteAuth: class RemoteAuth:
def __init__(self, app): self.app = app def __init__(self, app): self.app = app
@@ -732,6 +737,8 @@ def api_approval(body: ApprovalIn):
@app.websocket("/ws") @app.websocket("/ws")
async def websocket(ws: WebSocket): async def websocket(ws: WebSocket):
# WebSocket 不受 CORS 约束,需自行校验 Origin(非浏览器客户端不带 Origin,放行;--key 远程模式由 RemoteAuth 的 Basic 鉴权把关)
if (origin := ws.headers.get("origin")) and not args.key and not LOCAL_ORIGIN.match(origin): return await ws.close(code=1008)
await ws.accept() await ws.accept()
ws_clients.add(ws) ws_clients.add(ws)
try: try:
+11 -5
View File
@@ -7,18 +7,21 @@
* **定义**:凡是经过行动验证的有效配置、避坑指南、关键路径,在重构(Refactoring/GC)时**严禁丢弃**。 * **定义**:凡是经过行动验证的有效配置、避坑指南、关键路径,在重构(Refactoring/GC)时**严禁丢弃**。
* **操作**:可以压缩文字、可以迁移层级(从 L2 移到 L3),但绝不能丢失信息的准确性和可追溯性。 * **操作**:可以压缩文字、可以迁移层级(从 L2 移到 L3),但绝不能丢失信息的准确性和可追溯性。
* 记忆修改时请极度小心,尽量不要overwrite或code run。只能少量patch,改不动宁愿不改。 * 记忆修改时请极度小心,尽量不要overwrite或code run。只能少量patch,改不动宁愿不改。
* 错误、过时信息不在保护范围内,应立刻遗忘(删除)而非在记忆中留下标记,除非转化为简短纠错经验
3. **禁止存储易变状态 (No Volatile State)** 3. **禁止存储易变状态 (No Volatile State)**
* **定义**:严禁存储随时间/会话高频变化的数据。 * **定义**:严禁存储随时间/会话高频变化的数据。
* **示例**:当前时间戳、临时 Session ID、正在运行的 PID、某个具体绝对路径、连接的设备信息 * **示例**:当前时间戳、临时 Session ID、正在运行的 PID、某个具体绝对路径、连接的设备信息
* 清理记忆时发现易变状态应立刻删除
4. **最小充分指针 (Minimum Sufficient Pointer)** 4. **最小充分指针 (Minimum Sufficient Pointer)**
* 上层只留能定位下层的最短标识,多一词即冗余。 * 上层只留能定位下层的最短标识,多一词即冗余
> **绝对禁止写入:非用户要求的模型固有臆想规定或限制,如“不准删除,需要备份,需要比对sha”等等** * L4已经保留了所有会话记录,L2/L3仅允许归纳筛选后的精华信息
> **绝对禁止写入非用户要求的模型固有臆想规定或限制,如“不准删除,需要备份,需要比对sha”等等**
--- ---
## 记忆层级架构 ## 记忆层级架构
``` ```
L1: global_mem_insight.txt (极简索引层 - 严格控制 ≤30 行) L1: global_mem_insight.txt (极简索引层 - 严格控制 ≤30 行)
↓ 导航指向 (Pointer) ↓ 导航指向 (Pointer)
L2: global_mem.txt (事实库层 - 现短但会膨胀) L2: global_mem.txt (精简事实+文件指针)
↓ 详细引用 (Reference) ↓ 详细引用 (Reference)
L3: ../memory/ (记录库层 - 包含 .md/.py 等各类文件) L3: ../memory/ (记录库层 - 包含 .md/.py 等各类文件)
L4: ../memory/L4_raw_sessions/ (历史会话层 - scheduler反射自动收集,可定位过往上下文) L4: ../memory/L4_raw_sessions/ (历史会话层 - scheduler反射自动收集,可定位过往上下文)
@@ -43,9 +46,11 @@ L4: ../memory/L4_raw_sessions/ (历史会话层 - scheduler反射自动收集,
### L2:全局事实库 (global_mem.txt) ### L2:全局事实库 (global_mem.txt)
**职责**:存储全局环境性事实(路径、凭证、配置、常量等)。 **职责**:存储全局环境性事实(路径、凭证、配置、常量等)。
**特征**: **特征**:
- 趋势:随环境扩展而膨胀(可接受) - 趋势:随环境扩展而少量膨胀、大量事实只留事实文件路径
- 内容:按 `## [SECTION]` 组织的事实条目 - 内容:按 `## [SECTION]` 组织的事实条目
- 同步:变化时更新 L1 的相应 TOPIC 导航行,只能导航 - 同步:变化时更新 L1 的相应 TOPIC 导航行,只能导航
- 维护时过期事实应当清理/替换而非仅标注
- 同一事件大量事实应当另外使用文件存储,L2仅留文件路径
**禁止**:禁止存储易变状态、禁止存储猜测、严禁存储大模型可推理的通用常识 **禁止**:禁止存储易变状态、禁止存储猜测、严禁存储大模型可推理的通用常识
--- ---
### L3:任务级精简记录库 (../memory/) ### L3:任务级精简记录库 (../memory/)
@@ -80,7 +85,8 @@ L4: ../memory/L4_raw_sessions/ (历史会话层 - scheduler反射自动收集,
是『环境特异性事实』? (IP、非标路径、凭证、ID、API 密钥等,大模型 Zero-shot 无法生成准确) 是『环境特异性事实』? (IP、非标路径、凭证、ID、API 密钥等,大模型 Zero-shot 无法生成准确)
├─ YES → L2 (global_mem.txt) ├─ YES → L2 (global_mem.txt)
│ 然后 → 按频率归入 L1 第一层(key→value)或第二层(仅关键词) │ 量大 → 独立文件,L2 留路径
| 然后 → L1中增加或归纳融入1个索引词
│ │
└─ NO └─ NO
↓ ↓