feat(v2): T-M1 采纳 pi 会话树设计——AgentSession fork 分叉(parent_id/fork_point 血统 + 值拷贝隔离)

- SessionStore.fork(sid, turn_index, title):值拷贝 turns[:n+1] 生成新会话,
  原会话不变;新会话记录 parent_id/fork_point(pi 的 id/parentId 树思想);
  拷贝式而非共享存储引用——规避并发写冲突,会话体量小冗余可接受
- 旧会话数据无血统字段自然兼容(dict.get 语义,零迁移,对齐 pi 的版本迁移纪律)
- 新增 POST /agent/sessions/{sid}/fork 端点(404 = 会话不存在/分叉点越界)
- 新增 tests/test_session_fork.py 6 项(拷贝正确性/缺省语义/越界/深拷贝/
  旧数据兼容/端点 200+404)
This commit is contained in:
tzt
2026-09-19 09:29:57 +08:00
parent 819c5cceaf
commit f7e8273434
3 changed files with 147 additions and 0 deletions
+18
View File
@@ -740,6 +740,24 @@ try:
raise HTTPException(status_code=404, detail=f"会话不存在: {sid}")
return sess.view()
@app.post("/agent/sessions/{sid}/fork", tags=["agent"])
async def agent_session_fork(sid: str, req: dict = None):
"""从会话分叉新会话:{"turn_index": 截止轮下标(缺省=全部轮), "title"}。
T-M1(采纳 pi 会话树设计):值拷贝历史轮次,原会话不变;
新会话带 parent_id/fork_point 血统字段。
"""
_check_id(sid, "会话 ID")
from gateway.agent import get_session_store
body = req or {}
turn_index = body.get("turn_index")
sess = get_session_store().fork(sid, turn_index,
str(body.get("title") or ""))
if sess is None:
raise HTTPException(status_code=404,
detail=f"会话不存在或分叉点越界: {sid}")
return sess.view()
@app.delete("/agent/sessions/{sid}", tags=["agent"])
async def agent_session_delete(sid: str):
_check_id(sid, "会话 ID")