pref(session): 会话目录化与 session_asset 发送链路落地#330
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
|
/code 修复comment的问题,并提高覆盖测试率 |
|
已按触发指令完成“修复 comment 问题 + 提高覆盖测试率”,并已推送到当前 PR 分支 本次修复
测试补充
验证结果
|
Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: phantom5099 <245659304+phantom5099@users.noreply.github.com>
|
/review |
| } | ||
| defer func() { _ = reader.Close() }() | ||
|
|
||
| data, err := io.ReadAll(io.LimitReader(reader, maxSessionAssetReadBytes+1)) |
There was a problem hiding this comment.
当前只对单个 session_asset 做了 20 MiB 限制,但没有限制单次请求内所有附件的累计大小。当一条消息包含多个 session_asset(每个都低于上限)时,会在构建请求阶段累计读入并 base64 膨胀,容易导致内存和请求体体积突增,触发 provider 413/超时或本地内存峰值问题。建议增加总量上限(例如在 BuildRequest/转换流程中累计字节并提前失败)。
| // filePath 生成会话 ID 对应的 JSON 文件路径。 | ||
| func (s *JSONStore) filePath(id string) string { | ||
| return filepath.Join(s.baseDir, id+".json") | ||
| return filepath.Join(s.sessionDir(id), sessionFileName) |
There was a problem hiding this comment.
filePath 从 <sessionID>.json 切换到 <sessionID>/session.json,但本 PR 没有提供旧格式读取兼容或迁移逻辑;同时 ListSummaries 仅遍历目录项。结果是升级后历史会话会在列表中“消失”,并且 Load 无法读取旧会话文件,属于用户可见的数据回归。建议至少增加向后兼容读取(优先新路径,回退旧路径)或在启动阶段执行一次可回滚的迁移。
| summaries := make([]Summary, 0, len(entries)) | ||
| for _, entry := range entries { | ||
| if entry.IsDir() || filepath.Ext(entry.Name()) != ".json" { | ||
| if !entry.IsDir() { |
There was a problem hiding this comment.
会话存储切到目录结构后,这里只扫描目录项,且 Load 也只读 <session-id>/session.json。如果用户本地仍有旧版平铺 *.json 会话文件,升级后会直接“不可见/不可加载”。建议至少补一个兼容迁移路径(读取旧文件并迁移)或在启动阶段给出明确迁移提示。
|
/code 提高测试覆盖率 |
完成情况已按“提高测试覆盖率”完成补测并推送到当前 PR head 分支 变更摘要
主要补齐分支:
验证结果
提交信息
|
Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: phantom5099 <245659304+phantom5099@users.noreply.github.com>
|
@xgopilot 仔细审查给定的 PR 代码变更。该 PR 将会话存储结构由平铺文件改为了目录结构,引入了二进制附件的本地存储,并在大模型请求时进行 Base64 转换。你的核心任务是寻找内存溢出风险(OOM)、向后兼容性断裂、跨平台文件锁冲突、路径穿越漏洞以及文件句柄泄漏。请忽略基础语法格式,直击架构隐患。 Review Checkpoints (重点审查清单)请严格按照以下清单对代码进行交叉对比和逐行审查:
Output Format请以 Markdown 格式输出你的审查报告。要求直奔主题,结构如下:
如果你在上述清单中未发现问题,请在报告中明确回复“针对 [第 X 项],代码已通过严格审查,未发现逻辑漏洞”。 |
🛑 致命缺陷 (Blockers)
func (s *JSONStore) legacyFilePath(id string) string {
return filepath.Join(s.baseDir, id+".json")
}
func (s *JSONStore) Load(ctx context.Context, id string) (Session, error) {
data, err := os.ReadFile(s.filePath(id))
if err != nil && errors.Is(err, os.ErrNotExist) {
data, err = os.ReadFile(s.legacyFilePath(id))
}
if err != nil {
return Session{}, err
}
// decode...
}
func (s *JSONStore) ListSummaries(ctx context.Context) ([]Summary, error) {
// 现有目录扫描保留
// 额外扫描 baseDir 下 *.json(排除 assets 元数据)并合并去重(目录优先)
}
const (
maxSessionAssetBytes int64 = 5 * 1024 * 1024 // 单图硬上限
maxSessionAssetsTotalBytes int64 = 12 * 1024 * 1024 // 单请求总上限(原始字节)
)
func BuildRequest(ctx context.Context, cfg provider.RuntimeConfig, req providertypes.GenerateRequest) (Request, error) {
var total int64
for _, m := range req.Messages {
msg, used, err := ToOpenAIMessageWithBudget(ctx, m, req.SessionAssetReader, maxSessionAssetsTotalBytes-total)
if err != nil { return Request{}, err }
total += used
if total > maxSessionAssetsTotalBytes {
return Request{}, fmt.Errorf("session assets total exceeds %d bytes", maxSessionAssetsTotalBytes)
}
payload.Messages = append(payload.Messages, msg)
}
return payload, nil
}
|
@xgopilot 不要兼容读旧会话,然后把其他问题给我整理成一份清单输出 |
其他问题清单(按严重级别)已按你的要求排除“兼容读取旧平铺会话”项,仅保留其余问题。
结论本轮可优先修复顺序: |
@xgopilot 修复这条comment中提到的问题 |
修复完成已按你在该评论里要求的 3 项问题完成修复,并已推送到当前 PR 分支 提交: 本次修改
测试更新
验证结果
未做项:未引入“旧平铺会话兼容读取/迁移”逻辑(按你当前触发评论要求,本轮仅修复这 3 项)。 |
…path guard Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: phantom5099 <245659304+phantom5099@users.noreply.github.com>
|
/code 将测试覆盖率提高100% |
|
已按指令补充测试并推送到当前 PR 分支 结果
验证
未达成项说明当前仓库整体覆盖率及相关包覆盖率仍未达到 100%。剩余低覆盖主要集中在 |
Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: phantom5099 <245659304+phantom5099@users.noreply.github.com>
本次完成内容
本次改动围绕“会话级附件存储 + provider 发送”完成了主体闭环,重点是把会话数据和附件统一收敛到同一会话目录,并打通
session_asset到模型请求阶段的读取与转换。1. 会话存储结构升级为“会话目录模式”
*.json调整为:projects/<workspace-hash>/sessions/<session-id>/session.jsonprojects/<workspace-hash>/sessions/<session-id>/assets/JSONStore的Save/Load/ListSummaries已适配新结构,列表读取改为扫描会话子目录中的session.json。2. 新增会话级附件存储能力
在
internal/session新增AssetStore能力,并由JSONStore实现:SaveAsset(ctx, sessionID, reader, mimeType)Open(ctx, sessionID, assetID)Stat(ctx, sessionID, assetID)实现细节:
assets/<asset-id>.binassets/<asset-id>.jsonsessionID/assetID增加格式校验,阻断路径穿越image/*)3. runtime 注入会话附件读取器
runtime.Service新增可注入的SessionAssetStore,并在每轮 provider 请求快照中注入SessionAssetReader(按当前sessionID绑定)。这样 provider 在编码消息时可以按会话读取
session_asset,而不需要接触本地绝对路径。4. provider 支持
session_asset图片发送chatcompletions适配器完成以下变更:ToOpenAIMessage支持读取session_assetsession_asset不支持”阻断逻辑5. 测试与文档同步
session相关测试路径到新会话目录结构session_asset编码发送路径测试结果
已通过:
go test ./internal/sessiongo test ./internal/runtimego test ./internal/provider/openaicompat/chatcompletionsgo test ./internal/provider/openaicompatgo test ./internal/app