Description 目标问题
附件无法删除导致资源泄漏:用户上传附件后无法删除,切换会话或取消上传时服务端文件残留,缺乏生命周期管理。
切换到不支持图片的模型后历史图片导致请求失败:用户上传图片后切换模型(如从 Claude 切到纯文本模型),历史消息中的图片内容会导致上游 API 返回 400 错误。
新会话创建期间被自动切换:Web 端创建新会话时,fetchSessions 回调会自动切换到第一个会话,导致用户被意外跳转。
设计方案
附件删除
从 RuntimePort 拆出 SessionAssetPort 独立接口(接口隔离原则),包含 SaveSessionAsset、OpenSessionAsset、DeleteSessionAsset 三个方法。
Gateway 注册 DELETE /api/session-assets/{sessionID}/{assetID} 端点,支持多工作区路由和认证。
CLI Bridge 实现 DeleteSessionAsset:校验身份 → 查找会话 → 通过 sessionAssetDeleter 接口删除文件。
Web 端取消上传/移除附件时调用 deleteSessionAsset 释放服务端资源。
修复 SaveSessionAsset 缺少会话存在性校验的问题(不存在的 sessionID 之前静默创建文件,现在返回 ErrRuntimeResourceNotFound)。
修复 OpenSessionAsset 缺少 os.ErrNotExist 映射的问题。
图片输入模型兼容降级
Runtime 新增 currentInputParts 字段记录当前用户输入的原始 Parts。
在 session_start 阶段调用 rejectUnsupportedCurrentImageInput:若当前模型不支持图片但用户上传了图片,直接拒绝并返回明确错误。
在 prepareTurnBudgetSnapshot 中调用 projectImagesForModelRequest:对历史消息中的图片做投影降级——不支持图片的模型将历史图片替换为占位文本 [历史图片已省略:当前模型不支持图片输入],不修改持久化消息,仅影响发送给模型的内容。
新会话防自动切换
Web 端 useSessionStore 新增 _pendingNewSession 内部状态标记。
用户创建/切换新会话时置 true,阻止 fetchSessions 回调自动切换到第一个会话。
会话绑定成功后置 false。
落地清单
Gateway:
从 RuntimePort 拆出 SessionAssetPort 独立接口
新增 DeleteSessionAsset 方法和 DeleteSessionAssetInput 结构体
注册 DELETE /api/session-assets/{sessionID}/{assetID} HTTP 端点
多工作区运行时适配 SessionAssetPort,检测下游是否实现该接口
新增 sessionAssetDeleteMethod 到 HTTP ACL 白名单
新增 ErrRuntimeSessionAssetDeleteNotSupported 错误码
CLI Bridge:
实现 DeleteSessionAsset 全流程
修复 SaveSessionAsset 缺少会话存在性校验
修复 OpenSessionAsset 缺少 os.ErrNotExist 映射
Runtime:
新增 currentInputParts 字段
实现 projectImagesForModelRequest 图片投影降级
实现 rejectUnsupportedCurrentImageInput 拒绝不支持的图片输入
新增 hasImageCapability / partIsImage 辅助函数
Web:
新增 deleteSessionAsset() API 方法
新增 session_asset_delete 方法名常量
ChatInput 取消上传时调用 deleteSessionAsset
useSessionStore 新增 _pendingNewSession 防止自动切换
验收标准
附件删除全链路可用:Web 取消上传 → Gateway 路由 → CLI Bridge 执行删除
删除后 OpenSessionAsset 返回 not found
SaveSessionAsset 对不存在的会话返回 ErrRuntimeResourceNotFound
图片投影不污染持久化消息,仅影响模型请求
不支持图片的模型收到占位文本而非图片数据
当前输入含不支持的图片时拒绝并返回明确错误
新会话创建期间不被 fetchSessions 自动切换
go build ./... 通过
go test ./internal/gateway/... ./internal/runtime/... ./internal/cli/... 通过
测试场景
正常删除附件后再次 Open 返回 not found
对不存在的 sessionID 执行 Save 返回 not found
模型支持图片时历史图片正常传递
模型不支持图片时历史图片被替换为占位文本
当前输入含图片但模型不支持时拒绝
新会话创建期间 fetchSessions 不触发自动切换
破坏性变更说明
RuntimePort 移除了 SaveSessionAsset / OpenSessionAsset 方法,拆入独立的 SessionAssetPort 接口。所有 RuntimePort 实现方需适配:不再需要实现附件方法,改为实现 SessionAssetPort。
关联
风险与回滚
风险:SessionAssetPort 拆分是破坏性接口变更,所有 RuntimePort 实现方需适配
风险:SaveSessionAsset 行为变更(不存在的 sessionID 从静默创建变为返回错误)
回滚:恢复 RuntimePort 中的附件方法,移除 SessionAssetPort,移除图片投影逻辑
Reactions are currently unavailable
You can’t perform that action at this time.
目标问题
设计方案
附件删除
图片输入模型兼容降级
新会话防自动切换
落地清单
验收标准
测试场景
破坏性变更说明
关联
风险与回滚