qwen-code WebShell 会话上下文模型:Standalone PR5 中 workspace / standalone / Live 三态会话的显式表示与切换设计

📅 发布时间:2026/9/14 17:27:47
qwen-code WebShell 会话上下文模型:Standalone PR5 中 workspace / standalone / Live 三态会话的显式表示与切换设计
qwen-code WebShell 会话上下文模型Standalone PR5 中 workspace / standalone / Live 三态会话的显式表示与切换设计【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code导读本文基于 docs/plans/2026-08-28-standalone-pr5-webshell-context.md 展开。该方案是 qwen-code daemon 会话体系向「无工作区standalone会话」演进的关键一环它让 daemon React Provider 显式区分并切换 workspace、standalone、Live 三类会话同时保持现有 WebShell 入口不变。读完本文你将掌握DaemonProductSessionContext产品上下文契约的语义、三类会话各自的创建/恢复/所有权验证路径、会话切换的加载骨架状态机以及 standalone 会话独有的结果未知恢复与目录错误码处理并可从 SDK 源码与 WebShell 测试中验证这些设计。一、方案背景与目标在 PR5 之前的 WebShell 会话模型中Provider 以workspaceCwd工作区路径为核心路由依据daemon 侧会话也围绕工作区组织。随着 standalone无项目工作区会话与 Live 会话的引入原有的「单一工作区语义」不再能表达三类会话的差异workspace 会话绑定一个确切的cwd运行于某个工作区项目内standalone 会话不绑定任何项目工作区projectless拥有独立的 projectless 输出目录与工作目录Live 会话由 qwen-live 等 Live 运行时托管可信运行时身份来自 daemon 侧持久化源验证。PR5 的目标非常聚焦让 daemon React Provider 显式表示并切换这三类会话同时保持当前 WebShell 入口不变。实现从main分支开始——WebShell 通过qwen-code/webui/daemon-react-sdk消费该 Provider。方案明确指出不会复制进行中的 WebShell cutover切换迁移后续的重命名阶段可以原样携带 Provider 变更而不产生架构性改动。设计文档中提及的 post-#9129 加载骨架模型loading-skeleton model指会话切换期间以「目标会话 id 上下文」先行发布、加载完成后再提交客户端的 UI 状态模型PR5 完整继承了这一模型。二、产品上下文契约DaemonProductSessionContext方案首先定义了产品上下文契约类型它是全文的核心枢纽type DaemonProductSessionContext | { kind: workspace; cwd: string } | { kind: standalone } | { kind: live };围绕这一类型文档明确了三个权威边界源码中可以一一对应sessionContext是产品与路由的权威authority。它决定会话去哪条路径创建/恢复也决定会话属于哪一类产品上下文。connection.context保持为既有的模型上下文窗口快照。也就是说「产品会话上下文」workspace/standalone/live与「模型上下文窗口」是两个不同维度互不混淆。connection.workspaceCwd只在产品 workspace 会话时设置。内部 Conversations 运行时的 cwd永远不会被暴露为项目workspace——这是防止内部实现细节泄漏到产品层的硬性约束。从 packages/sdk-typescript/src/daemon/standalone-sessions.ts 可以看到SDK 层对 standalone 会话的字段校验同样强调sourceType: standalone与context: { kind: standalone }必须同时成立否则抛出DaemonStandaloneProtocolError。这印证了「上下文是权威」的设计在协议校验层已被强制执行。兼容性legacyworkspaceCwd的转换规则旧调用方可能仍会继续传workspaceCwd。PR5 的兼容规则如下仅传 legacyworkspaceCwdProvider 将其一次性转换为 workspace 上下文显式 workspace 上下文 同时提供 legacy cwd两者必须在路径规范化后一致否则判定为冲突standalone / Live 上下文 提供 legacy cwd拒绝reject该 legacy cwd不允许混用两者都不提供保留既有 primary-workspace主工作区行为作为默认回退。在 packages/web-shell/client/daemon/session/actions.ts 中可以看到sessionContextKey与DaemonProductSessionContext类型被实际导入使用且actions.ts中存在大量「当前上下文为空或非 workspace」的判定分支如current.sessionContext ! undefined current.sessionContext.kind ! workspace说明该类型已贯穿 Provider 的动作层。三、创建与恢复分发Create / Load / Resume Dispatch三类上下文对应三条完全不同的创建/恢复路径PR5 以表格形式给出了权威分发矩阵产品上下文创建加载与恢复所有权证明Workspace既有的通用 create精确 cwd既有的通用 load/resume精确 cwd由调用方/Provider 选择的确切 ordinary 运行时StandaloneDaemonSessionClient.createStandaloneloadStandalone/resumeStandaloneSDK 运行时对专属 standalone 响应的校验Live不由本 Provider 创建针对唯一可信kind: live运行时的通用 load/resume能力运行时身份 daemon 侧持久化源校验关键约束显式上下文永不回退到 primary workspace。以下三种失败场景必须在发出会话请求之前失败standalone 能力缺失missing standalone capabilityLive 运行时缺失 / 不受信任 / 存在多个歧义运行时zero / multiple / untrusted上下文与 legacy cwd 冲突context/cwd conflict。从 SDK 源码可以验证 standalone 路径的底层实现。在 packages/sdk-typescript/src/daemon/DaemonSessionClient.ts 中三个静态工厂方法被逐一实现createStandalone(client, options)→ 调用client.createStandaloneSession(options)以lastEventId: 0、当前eventEpoch构造新客户端loadStandalone(client, sessionId, request, clientId)→ 调用client.loadStandaloneSession(...)后经createStandaloneRestoredClient(client, restored, true)构造并立即hydrateReplaySnapshot()水合回放快照includeReplaytrue带回放resumeStandalone(...)→ 调用client.resumeStandaloneSession(...)以 includeReplayfalse 构造不带回放。createStandaloneRestoredClient会从恢复响应中解构state、hasActivePrompt、compactedReplay、liveJournal、historyHasMore、historyAnchorRecordId、replayDegraded、partial、replayError、lastEventId、eventEpoch等字段并选择性携带replaySnapshot与回放完整性标记最终构造DaemonSessionClient——这正是「SDK 运行时校验 dedicated standalone 响应」的所有权证明落地之处。在 packages/sdk-typescript/src/daemon/DaemonClient.ts 中createStandaloneSession的实现进一步揭示了底层细节首先requireCapability(STANDALONE_SESSIONS_CAPABILITY)检查能力位对应standalone_sessions_v1定义于 standalone-sessions.tssessionId 缺省时使用globalThis.crypto.randomUUID()生成并小写化发起POST /standalone/sessions若失败且错误不属于「创建结果未知outcome unknown」原样抛出否则执行recoverStandaloneCreation(sessionId)精确查询恢复并抛出DaemonStandaloneCreationOutcomeUnknownError携带sessionId、recovery与originalError。DaemonStandaloneCreationRecovery的四种状态creating/existing/absent/unknown定义在 standalone-sessions.ts与 PR5 文档「生成的 UUID 与精确查找恢复结果记录进 connection 状态」的描述完全一致。四、切换语义继承 post-#9129 的加载骨架模型PR5 明确沿用 post-#9129 的 loading-skeleton 模型会话切换被拆成 5 个步骤捕获新的转换代数transition generation发布目标 session id 与上下文分离detach上一个客户端清空旧 transcript展示目标会话的加载态仅当转换仍然是最新current时才提交恢复的客户端、回放、standalone 工作目录状态与警告失败时保持目标 id/上下文可见并展示结构化错误不恢复上一个会话no rollback过期的成功客户端分离并丢弃其回放、警告与恢复状态stale-client detach。同样重要的还有「上下文持久性」规则reload刷新、reconnect重连、live-journal repair日志修复、invalid-client reattachment非法客户端重挂都复用存储的上下文绝不允许从缺失的 cwd 重建上下文。这保证了任何恢复路径都不会把 standalone/Live 会话错误地解释成 workspace。在 packages/web-shell/client/daemon/session/actions.ts 中可以看到 Provider 通过sessionContextKey(currentSessionContext) sessionContextKey(targetSessionContext)判断上下文是否变化并在变化时携带sessionContext: targetSessionContext发布目标状态——这正是「捕获新转换代数并发布目标上下文」的实现形态。而 DaemonSessionProvider.test.tsx 中大量sessionContext: { kind: standalone }/{ kind: live }/{ kind: workspace, cwd: ... }的断言覆盖了 workspace → standalone → workspace/Live 的切换场景。五、Standalone 状态管理结果未知恢复与目录错误码5.1 创建结果未知Outcome Unknown的处理standalone 创建与 workspace 创建最大的不同在于网络失败/超时后服务端可能已经创建成功客户端却不知道结果。PR5 的处理原则是DaemonStandaloneCreationOutcomeUnknownError原样重新抛出rethrown intact不被吞掉也不被包装当 create 拥有一个空 connection 时生成的 UUID 与精确查找恢复结果同时记录进 connection 状态供上层判断会话处于creating/existing/absent/unknown哪一种在活跃会话旁发生的 detached create 失败不触碰活跃 connection恢复信息只随结构化错误携带Provider 不重试 create不将 standalone create 包进通用的 30 秒 action 超时——因为通用超时可能在 SDK 必需的精确查找exact lookup完成之前就拒绝请求导致误判。5.2 目录状态与错误码透传成功的 standalone create/load 会把 SDK 提供的projectlessOutputDirectory与workingDirectory存入standalone 专属的 connection 字段recreated警告只属于当前目标会话若被其他转换取代则被丢弃standalone 目录错误码从结构化 daemon 错误体中拷贝进 connection 状态这样 PR6 可以直接依据错误码展示「修复目录」或「终端指引」无需解析字符串——这是面向可维护性的关键设计避免 UI 层做脆弱的文本匹配。SDK 侧的类型定义与之一一对应standalone-sessions.tsexport interface DaemonStandaloneWorkingDirectory { state: ready | recreated; warnings?: string[]; } export interface DaemonStandaloneFields { sourceType: standalone; context: { kind: standalone }; projectlessOutputDirectory: string; workingDirectory: DaemonStandaloneWorkingDirectory; }DaemonClient.repairStandaloneSessionDirectory对应POST /standalone/sessions/:id/repair-directory路由DaemonClient.ts返回DaemonStandaloneDirectoryResult正是 PR6 目录修复入口的协议基础。validateWorkingDirectory校验state只能是ready | recreated且warnings必须为字符串数组说明「recreated 警告」的协议形态在 SDK 解析层已被严格约束。六、Workspace 隔离非 workspace 会话跳过哪些能力对于 standalone 与 Live 会话Provider 必须跳过一切依赖工作区的能力PR5 给出的清单如下跳过的workspace-scopedsession-less workspace providers无会话工作区 Providerskills技能ACP preheat预热Git statusGit 状态workspace event invalidation工作区事件失效仍然可用的session-scopedsession-scoped supported commands会话级支持命令context/model status上下文/模型状态Goal state目标状态transcript replay转写回放prompts提示词permissions权限heartbeat心跳在 actions.ts 中可以观察到对应的守卫逻辑preserveWorkspaceMetadata current.sessionContext undefined || current.sessionContext.kind workspace——即只有 workspace 上下文或未显式指定上下文的 legacy 调用才保留工作区元数据standalone/Live 上下文则关闭相关工作区行为。PR5 明确指出当前可见的 WebShell 在 PR5 中还没有 standalone 入口。PR6 必须在把 Global New Chat 和 Recents 接入新上下文之前先对 App 级工作区功能做 gate门控。但 PR5 已经暴露了足够多的类型化状态使得该 gate 可以不把内部运行时 cwd 解释为 workspace——这正是第一节「内部 cwd 永不暴露为项目」约束的延续。七、兼容性与迁移路径PR5 的兼容性承诺可以概括为「旧调用零破坏」既有 Provider props 与 action 调用保持有效workspace 行为与 primary fallback仅对未显式提供上下文的调用方保持不变公开的 daemon React SDK导出上下文类型与 standalone 状态类型如DaemonProductSessionContext、DaemonStandaloneFields、DaemonStandaloneWorkingDirectory、DaemonStandaloneCreationOutcomeUnknownError等见 packages/sdk-typescript/src/daemon/standalone-sessions.ts 与 packages/sdk-typescript/src/daemon/DaemonClient.ts不新增任何 daemon 路由或 SDK validator——复用既有 HTTP 能力后续 WebShell provider cutover 只是移动这些文件不做架构性改动发布直接依赖 standalone SDK 方法的 WebShell 包之前需要把其 SDK peer 最低版本对齐到第一个包含 PR4 的已发布 SDK 版本因为 standalone 能力由 PR4 引入。从 packages/sdk-typescript/test/unit/daemon-public-surface.test.ts 与 packages/sdk-typescript/test/unit/DaemonClientStandalone.test.ts 的存在可以看出「公开类型导出与浏览器 bundle」确实被作为独立的验证面纳入测试体系。八、验证矩阵测试覆盖哪些行为PR5 给出了聚焦测试的覆盖清单是验证设计正确性的直接依据上下文规范化与冲突拒绝context normalization conflict rejectionworkspace / standalone / Live 的精确路由选择exact route selectionstandalone 能力缺失、Live 运行时 zero/multiple/untrusted 失败且不发出回退请求workspace → standalone → workspace/Live 的切换快速超驰rapid supersession、过期客户端分离、仅目标会话的回放/警告加载骨架的失败语义无回滚reload / reconnect 复用存储上下文outcome-unknown 恢复状态且无 create 重试、无外层超时遮蔽recreated 目录状态与结构化目录错误码非 workspace 上下文下无 workspace providers / skills / Git / preheat / 事件失效legacy workspace 调用方行为不变、Provider 转换受控公开类型导出与浏览器 bundle。这些断言在 packages/web-shell/client/daemon/session/DaemonSessionProvider.test.tsxstandalone/Live/workspace 上下文的切换、失败语义、recreated 状态等大量用例与 packages/sdk-typescript/test/unit/DaemonClientStandalone.test.tsSDK 层 standalone 创建/加载/恢复与 outcome-unknown 恢复中均有对应实现。推荐的验证命令集PR5 明确列出了发布前的验证范围可归纳为以下几条命令思路具体以仓库内 npm scripts 为准WebUI Provider/action 聚焦测试WebUI build / typecheck / lintWebShell Provider 集成测试WebShell build / typecheck / lint / format根目录 build 与 typecheckSDK / WebShell 的 public-surface 与 browser-bundle 检查。九、范围边界PR5 刻意不做的事PR5 是一个严格收敛的 PR以下可见产品流明确留到 PR6Global New Chat、Recents最近会话生命周期菜单lifecycle menusarchive / delete / repair 控制deep links深链standalone uploads独立上传project-control hiding项目控件隐藏同时PR5不改变 daemon 生命周期行为也不重建已被回滚的事务性会话切换协调器transactional session-switch coordinator。也就是说PR5 只做「表示层显式建模 路由分发 状态机切换」把可见 UI 流与更底层的 daemon 变更留给后续迭代。十、小结PR5 的价值在于一次干净的类型化收敛DaemonProductSessionContext让 workspace / standalone / Live 三类会话首次在 Provider 层获得一等公民地位并配套了完整的创建/恢复分发、切换状态机、standalone 结果未知恢复、目录错误码透传与 workspace 能力隔离。它与 SDK 层 DaemonSessionClient / DaemonClient / standalone-sessions.ts 的协议实现严格对齐并在 DaemonSessionProvider.test.tsx 与 DaemonClientStandalone.test.ts 中得到系统性验证。对于希望深入 qwen-code 会话体系或在此基础上扩展 standalone UI 的开发者PR5 是理解「会话类型如何从工作区一元模型走向多态模型」的最佳切入点其后续演进PR6 的 Global New Chat、Recents 与生命周期管理也都建立在本文描述的上下文契约之上。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考