Qwen Code Daemon 多工作区会话导出:Workspace-Qualified Session Export 设计与实现解析
Qwen Code Daemon 多工作区会话导出Workspace-Qualified Session Export 设计与实现解析【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code导读本篇文章围绕 qwen-code 仓库中docs/design/daemon-multi-workspace-session-export.md设计方案展开深入剖析 daemon 如何让客户端从**显式选定的已注册工作区workspace**导出持久化会话。你将掌握新的GET /workspaces/:workspace/session/:id/export路由契约、workspace 选择与信任检查规则、workspace_session_export能力通告机制以及 SDK 层与遥测层对应的实现细节。文中所有结论均以当前仓库源码为据可直接对照 路由实现 与 SDK 客户端 进行验证。背景与动机为什么单一导出路由不够用了qwen-code 的 daemon 在设计上支持多工作区运行时multi-workspace runtime。在引入 workspace-qualified 导出之前客户端只能通过GET /session/:id/export导出会话而该路由**有意绑定在主工作区primary workspace**上。这带来两个实际问题当某个会话持久化在次工作区secondary workspace时直接复用主绑定路由会返回404更危险的是当同一个 session id 在多个工作区中都存在时旧路由可能选中错误的 transcript导致导出的内容张冠李戴。Issue #6378 因此要求客户端能够从一个显式选定的已注册工作区导出持久化会话。围绕这个目标该设计新增了四样东西新的复数路由GET /workspaces/:workspace/session/:id/export?formathtml|md|json|jsonl对应的能力标签workspace_session_export匹配的WorkspaceDaemonClientSDK 方法配套的使用文档。与此同时旧路由GET /session/:id/export继续保留且仍为主工作区绑定保证既有客户端的兼容性不被破坏。路由契约workspace 选择、格式参数与错误语义新增路由与选择规则新路由的完整形态为GET /workspaces/:workspace/session/:id/export?formathtml|md|json|jsonl其中:workspace选择器遵循仓库中既有的复数路由规则plural-route rule解析顺序为先按精确的已注册 workspace id 匹配再按 URL 编码的绝对 cwdcanonicalization 之后匹配。这一步在源码中由resolveQualifiedSessionTarget实现见 packages/cli/src/serve/routes/session.ts#L1295-L1328先用workspaceRegistry.getManagedEntryByWorkspaceId(selector)精确查找 id若 selector 是绝对路径则继续尝试getManagedEntryByWorkspaceCwd(selector)最后通过resolveWorkspaceRuntimeFromParam解析出目标运行时。选中的运行时必须受信任trusted——对于普通非 primaryruntime若runtime.trusted为假会直接返回 untrusted workspace 响应。值得注意的执行顺序是workspace 解析与信任检查先于 session 存在性与格式校验也就是说即使 session id 或 format 不合法也先保证不会把请求路由到错误的工作区。导出行为边界该路由只做一件事读取所选 workspace 的活动active持久化 JSONL 并导出。设计文档明确列出它不做的事情这些约束也对应了实现中handleSessionExport与resolveQualifiedSessionRuntime的代码路径见 packages/cli/src/serve/routes/session.ts#L1376-L1424 与 #L1508-L1603不搜索其他工作区也不回退到主工作区不解析 live owner、不启动 ACP、不附加客户端不加载 workspace 设置归档archived会话不可用归档导出由单独的/workspaces/:workspace/session/:id/archive/export路由承载见 session.ts#L5534-L5552。在成功路径上新路由复用与旧路由完全相同的 formatter、文件名清理、MIME 类型、缓存策略与附件头。从实现可以看到具体行为session.ts#L1577-L1585res .status(200) .set(Cache-Control, no-store) .set(X-Content-Type-Options, nosniff) .set(Content-Type, result.mimeType) .set(Content-Disposition, attachment; filename${filename}) .send(result.content);其中文件名会先经过filename.replace(/[\\\r\n]/g, _)清理防止响应头注入。错误契约新路由的错误响应复用既有的 export/storage 错误形状覆盖以下错误码HTTP 状态码错误码触发场景400workspace_mismatchworkspace 选择器无法解析为已注册工作区403untrusted_workspace选中的次工作区 runtime 不受信任400invalid_export_formatformat参数不在html/md/json/jsonl内响应体附带allowedFormats404session_not_found目标工作区中不存在该 session id409session_archived/session_archiving/session_conflict会话归档状态与导出目标冲突实现中parseSessionExportFormat对非法格式直接返回400 invalid_export_format并携带允许值列表session_not_found的 404 响应还会回传sessionId字段见 session.ts#L1587-L1593。能力通告与兼容性workspace_session_export新能力标签workspace_session_export在 packages/cli/src/serve/capabilities.ts#L442-L445 中声明为无条件unconditionalv1 能力// Workspace-qualified full session export from active persisted storage. // This is separate from session_export so clients do not infer the plural // route from the legacy primary-workspace export capability. workspace_session_export: { since: v1 },设计上做无条件的原因很务实复数路由对于受信任的单工作区主工作区同样有用可以通过 id 或 cwd 显式选中主工作区。信任仍然在每个请求上独立评估并不因为能力被通告就放行。该标签的独立性体现在三处关键约束与multi_workspace_sessions相互独立互不推断不能从session_export或workspace_qualified_rest_core推断出来——已发布的旧 daemon 会同时通告这两个旧标签但并不实现这条新路由因此客户端必须显式 pre-flight 检查workspace_session_export对应的归档导出能力是单独的workspace_archived_session_exportcapabilities.ts#L446-L449避免旧 daemon 把归档意图悄悄降级成活动 transcript。在兼容性层面当 SDK 直接调用者把新方法发往旧 daemon 时只会收到正常的 HTTP 错误不会产生任何意外行为。Web Shell 集成不在此变更范围内其既有的仅主工作区导出行为保持不变——这也意味着该能力的消费方目前主要是 SDK / REST 客户端。并发与安全设计归档协调器共享锁导出复用了既有的共享归档协调器锁shared archive-coordinator lock锁按 session id 键控见 session.ts#L1543 中archiveCoordinator.runSharedMany([sessionId], ...)。这样做的目的是在导出重放replay期间归档archive与删除delete操作不能移动或移除正在读取的文件。设计文档同时坦承该协调器保守地保持全局性不同工作区中相同 id 的会话即便文件彼此独立也可能发生串行化。把所有 archive/delete 锁键改为带 workspace 限定keying by workspace session id被明确列为超出本次变更范围的工作。全量导出与受信任边界与有界bounded的持久化 transcript 分页器不同全量导出会物化完整 transcript因此绝不提供给不受信任的次工作区。这也正是上述403 untrusted_workspace存在的原因不受信任的次工作区只能通过受控的分页接口读取有界 transcript而不能拿到全量导出。响应大小预算方面既有受信任导出没有新增的响应大小上限。设计文档解释若给 workspace 专属导出加一个限制会让复数路由与旧路由的 format 契约产生分歧diverge。安全边界仍由以下既有机制兜底daemon bearer 认证默认的 GET 读速率层级read-rate tier按请求执行的 workspace 信任检查。运行时移除竞态运行时移除runtime removal竞态使用请求解析时选中的那个 runtime而移除操作并不会删除 transcript 存储。因此导出不需要 runtime 租约lease也不会维持 ACP 子进程存活——导出的生命周期只依赖持久的 transcript 文件不依赖运行时进程。SDK 与可观测性WorkspaceDaemonClient.exportSessionSDK 方法SDK 层提供WorkspaceDaemonClient.exportSession其设计要点源码见 packages/sdk-typescript/src/daemon/DaemonClient.ts#L3283-L3295复用既有导出结果类型与格式类型DaemonSessionExportResult、DaemonSessionExportFormat不新增类型族总是使用原生 RESTmode: rest即使父客户端配置了 ACP transport 也不例外通过共享请求助手sessionExportRequest保留 token、客户端身份、超时、错误解析、Content-Type 与附件文件名行为保证与旧路由 SDK 调用体验一致。调用示例workspace-qualified 形态const result await client.exportSessionFromWorkspace( workspaceSelector, // 注册的 workspace id 或 URL 编码的绝对 cwd sessionId, { format: md }, );SDK 内部会将该调用归一为GET /workspaces/:workspace/session/:id/export请求若服务端 daemon 不支持则按普通 HTTP 错误处理。遥测规范化Daemon 遥测层将新路径规范化为GET /workspaces/:workspace/session/:id/export见 packages/cli/src/serve/server/telemetry.ts#L630并解码 session id使用中间件层完成的 workspace 解析结果记录所选 workspace 的 hash作为遥测属性。这样做的价值在于同一会话 id 在不同工作区中导出时遥测数据仍能准确归属到对应 workspace避免跨工作区的指标串扰。被否决的备选方案设计文档记录了四个被明确否决的替代方案理解它们有助于把握本方案的边界取舍按 live owner 路由单数导出对非活动inactive的持久化会话无法工作且重启后 owner 归属变得模糊给旧路由增加cwd查询参数会改变主工作区专属的兼容性契约也不如既有复数 workspace 路由风格一致miss 时回退主工作区当 id 冲突时可能导出另一个工作区的会话正是本设计要消除的错误允许不受信任的全量导出会绕过为持久化 transcript 分页器设计的有界读取策略破坏安全边界。验证测试矩阵与端到端手段该设计文档要求覆盖的验证面非常广结合仓库中的测试布局packages/cli/src/serve/multi-workspace-sessions.test.ts 等可以归纳为以下维度能力通告workspace_session_export是否按 v1 无条件通告且不与session_export/workspace_qualified_rest_core互相推断选择器id 与 cwd 两种选择路径的正确解析以及 unknown/missing 目标的错误响应同 id 隔离相同 session id 在不同 workspace 中存在时导出严格命中目标 workspace 的 transcript格式矩阵html/md/json/jsonl每种格式的导出内容与 MIME 类型响应头Cache-Control: no-store、X-Content-Type-Options: nosniff、Content-Disposition附件头与清理后的文件名信任与归档边界不受信任次工作区返回403、归档会话不可通过 active 路由导出、session_conflict等 409 语义无桥接活动导出过程不启动 ACP、不附加客户端、不加载 workspace 设置遥测归属规范化路径、session id 解码、workspace hash 属性SDK 传输与编码原生 REST 强制、URL 编码的 workspace cwd 与 session id、错误解析复用归档/删除协调与archiveCoordinator共享锁的并发行为。端到端验证采用隔离的 runtime 与 workspace 目录配合确定性的持久化 transcript从而保证导出结果可复现、可断言。小结daemon-multi-workspace-session-export设计为 qwen-code daemon 补齐了多工作区场景下的会话导出能力以GET /workspaces/:workspace/session/:id/export复数路由替代主绑定的单数路由通过精确 id → 规范化 cwd的选择规则与逐请求信任检查杜绝跨工作区串台同时保持旧路由、旧能力标签与既有错误契约的完全兼容。对于希望基于 REST/SDK 构建多工作区工具链的开发者这条路由与workspace_session_export能力标签是当前仓库中直接可用的标准入口如需进一步深入建议继续阅读 路由实现、能力声明 与 SDK 客户端 中的对应代码并结合 多工作区会话测试 验证行为边界。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考