設計解析:從 base64 內聯到文件名引用的存儲與生命周期)
qwen-code 會話附件引用Session Attachment References設計解析從 base64 內聯到文件名引用的存儲與生命周期【免費下載鏈接】qwen-codeAn open-source AI coding agent that lives in your terminal.項目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code導讀本文以 qwen-code 設計文檔 docs/design/session-attachment-references.md 為骨架系統講解 daemon 如何將圖片與任意文件字節落盤到會話附件目錄、以文件名引用attachment reference替代 base64/字節內聯從而避免在 daemon 請求、隊列、事件與回放replay數據中重復攜帶大體積負載的設計。讀完本文你將掌握附件引用的數據結構與命名規則、存儲位置與所有權模型、8 MiB 單文件上限等邊界約束以及session_attachments能力與/session/:id/attachmentsHTTP 路由在 TypeScript SDK 與 web-shell 中的真實調用形態。背景問題內聯負載帶來的重復膨脹在引入附件引用之前圖片 base64 與文件字節會被直接嵌入 daemon 的請求體、消息隊列、事件流和會話回放數據中。同一份附件在「上傳 → 排隊 → 轉發給 ACP 子進程 → 會話記錄回放」的每一跳都會被復制一份產生以下問題負載重復膨脹同一字節在多份請求/事件中反復出現內存與網絡開銷隨鏈路長度線性放大回放困難附件需要在 daemon 重啟后仍可預覽內聯字節若只存在于進程內存中重啟即丟失無統一出處不同客戶端各自攜帶字節缺少單一可信來源single source of truth。設計文檔給出的解法非常直接daemon 將圖片和任意文件字節寫入 workspace runtime 的附件目錄只返回一個基于文件名的引用后續所有鏈路傳遞的都是這個輕量引用。核心數據結構基于文件名的附件引用daemon 在存儲附件后返回如下引用對象{ type: image | resource; attachmentId: string; mimeType: string; size: number; }各字段含義字段說明typeimage圖片或resource任意文件資源attachmentId附件在存儲目錄中的文件名即引用本身mimeType附件 MIME 類型如image/png、application/pdfsize附件字節大小這一結構在 TypeScript SDK 中有完全對應的類型定義見 packages/sdk-typescript/src/daemon/types.ts#L4676-L4681export type DaemonSessionAttachmentReference Recordstring, unknown { type: image | resource; attachmentId: string; mimeType: string; size: number; };配套的讀取結果類型為DaemonSessionAttachmentData{ data: string; mimeType: string }data 為 base64 字符串見 packages/sdk-typescript/src/daemon/types.ts#L4683-L4686。命名規則與去重attachmentId 就是存儲文件名沒有獨立的 ID 體系重名文件采用平臺通用約定追加序號name (1).ext、name (2).ext以此類推不存在內存中的附件索引也沒有 sidecar 元數據MIME 類型與大小在讀取時直接從存儲文件推導從而避免了索引與實際文件之間的一致性維護成本。引用在鏈路中的流轉Prompt 與 mid-turn API 將引用對象隨隊列、事件、會話記錄元數據transcript metadata一起傳遞但只有真正向 ACP 子進程派發dispatch時才由 bridge 解析引用——即「引用輕量傳遞、字節延遲物化」。TypeScript 會話客戶端通過帶鑒權的附件路由authenticated attachment route讀取同一份引用用于預覽與回放渲染文本類資源解析為 ACP text其他文件格式解析為 ACP blob原始字節不會在瀏覽器中被解碼或改寫。對應實現中上傳與解析的橋接邏輯位于 packages/channels/base/src/DaemonChannelBridge.ts含removeAttachment鉤子、session_attachments能力預檢與按批次扇出上傳、以及不支持該能力時的圖片內聯降級路徑瀏覽器側的預覽/回放水合邏輯見 packages/web-shell/client/daemon/session/actions.ts 與 packages/web-shell/client/daemon/session/types.ts。存儲位置與所有權模型存儲路徑附件落盤于 workspace runtime 的附件目錄~/.qwen/tmp/workspace-hash/attachments/session-id/其中workspace-hash是 workspace 的哈希標識session-id是會話 ID使用自定義 runtime 目錄時路徑等價替換。所有權與鑒權resolved live-session owner 與客戶端授權保護每一次上傳upload、讀取read與移除remove操作關閉 daemon 或客戶端斷開連接只關閉文件句柄不會刪除文件——附件是持久化資源不隨連接生命周期消失永久刪除會話時其附件目錄一并移除避免孤兒文件殘留。生命周期策略刻意從簡設計上刻意排除了常見的復雜回收機制無 TTL附件不設過期時間無 sweeper沒有后臺清掃任務無 retained-media cache不維護媒體緩存無重啟重建索引daemon 重啟不需要重建任何附件索引。這與「無內存索引、無 sidecar 元數據」的設計一脈相承附件就是普通文件文件名即 ID狀態完全可由文件系統自身表達。大小限制與配額單個附件上限 8 MiB8 * 1024 * 1024字節會話沒有累計附件大小或數量上限。在源碼中單文件上限常量定義為SESSION_ATTACHMENT_MAX_ITEM_BYTES 8 * 1024 * 1024另有SESSION_ATTACHMENT_MAX_NAME_BYTES 255限制文件名長度見 packages/acp-bridge/src/sessionAttachments.ts#L13-L14。同一文件中還定義了受支持的圖片 MIME 類型集合image/bmp、image/gif、image/jpeg、image/png、image/webp。能力聲明與統一 HTTP 接口能力session_attachments統一能力標識為session_attachments在 serve 能力表中聲明為v1起可用見 packages/cli/src/serve/capabilities.ts#L57-L58。HTTP 表面/session/:id/attachments統一 HTTP 路由為/session/:id/attachments不存在session_media、/media或mediaId之類的兼容路徑——設計上明確只保留一套接口。TypeScript SDK 在 packages/sdk-typescript/src/daemon/DaemonClient.ts 中提供了四個對應的客戶端方法方法HTTP 路由作用uploadSessionAttachment(sessionId, data, name, mimeType, opts?)POST /session/:id/attachments?namename上傳字節請求體為原始字節流Content-Type即附件 MIME返回引用對象readSessionAttachment(sessionId, attachmentId, opts?)GET /session/:id/attachments/:attachmentId讀取附件內容返回{ data: base64, mimeType }listSessionAttachments(sessionId, opts?)GET /session/:id/attachments按上傳順序列出該會話當前存儲的全部附件引用removeSessionAttachment(sessionId, attachmentId, opts?)DELETE /session/:id/attachments/:attachmentId刪除附件返回{ removed: boolean }從實現細節可以印證設計中的幾個要點引用即文件名上傳 URL 以 query 參數name攜帶原始文件名daemon 據此落盤并返回attachmentId即存儲文件名見 DaemonClient.ts#L4080-L4102讀取時推導 MIME 與大小讀取響應的mimeType直接取自響應頭content-type缺失時回退為application/octet-stream見 DaemonClient.ts#L4128-L4163瀏覽器兼容讀取實現將Uint8Array分塊每塊0x8000字節再btoa編碼避免超出引擎參數上限注釋明確說明該包同時面向 Node 與瀏覽器環境mid-turn 預檢enqueueMidTurnMessage的文檔注釋提示調用方應先預檢session_attachments能力舊 daemon 會忽略 media 字段并丟棄圖片內容見 DaemonClient.ts#L4212-L4229。web-shell 會話層將這四個方法進一步封裝為uploadAttachment/readAttachment/listAttachments/removeAttachment含read_attachment、remove_attachment等權限動作并會在附加附件塊前預檢能力見 packages/web-shell/client/daemon/session/types.ts#L565-L581 與 packages/web-shell/client/daemon/session/actions.ts#L2546-L2625。實現層面的安全加固目錄防替換校驗雖然設計文檔保持簡潔但從實現可以看到一層額外的持久化安全措施附件存儲目錄被包裝為DurableAttachmentDirectory通過持有目錄句柄并校驗dev設備號與inoinode 號來檢測目錄是否被替換如符號鏈接攻擊或目錄被刪除重建校驗失敗時拋出Session attachment parent directory changed.見 packages/acp-bridge/src/sessionAttachments.ts#L23-L71。這層校驗與文檔「resolved live-session owner 和客戶端授權保護每一次上傳、讀取、移除」的所有權要求互相配合共同構成附件讀寫的安全邊界。小結引用式附件設計的取舍會話附件引用方案的核心取舍可以概括為以文件名替代字節內聯讓隊列、事件與回放數據只攜帶輕量引用字節只存在于磁盤與最終物化環節文件系統即狀態無索引、無 sidecar、無 TTL、無重建生命周期完全由會話刪除驅動換來極低的維護復雜度邊界清晰單文件 8 MiB、文件名 255 字節上限、統一session_attachments能力與/session/:id/attachments路由且不保留任何舊式/media兼容路徑。對需要集成 qwen-code daemon 的客戶端而言接入路徑非常明確預檢session_attachments能力 → 通過POST /session/:id/attachments上傳并拿到attachmentId→ 在 prompt/mid-turn 內容塊中攜帶引用 → 需要預覽或回放時通過GET路由按 ID 讀取、按需DELETE。相關類型定義、客戶端方法與橋接實現均可在 packages/sdk-typescript/src/daemon、packages/acp-bridge/src/sessionAttachments.ts 與 packages/channels/base/src/DaemonChannelBridge.ts 中進一步查閱?!久赓M下載鏈接】qwen-codeAn open-source AI coding agent that lives in your terminal.項目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考