返回 DeepSeek-Reasonix
SESSION_EXPORT.md
根目录 / docs / SESSION_EXPORT.md
1 # Complete session export / 会话完整导出
2
3 ## Ownership and snapshot / 数据归属与快照
4
5 Desktop captures an explicit host/session identity and accepted commit boundary
6 before opening the save dialog. `FlushThrough` waits only for that boundary;
7 cancelling its caller does not cancel shared persistence or execution. The Query
8 owner traverses the existing versioned display index forward in batches of at
9 most 100 records and hydrates content in ranges of at most 1 MiB. Provider working
10 sets and React resident items are never complete-export inputs. The default chat
11 window remains three pages of 32 records.
12
13 Desktop 在保存对话框出现前固定主机、会话和已接受提交边界。
14 `FlushThrough` 只等待该边界;取消等待不取消共享写盘或任务执行。
15 Query 使用既有版本化展示索引,每批最多 100 条、内容块最多 1 MiB。
16 完整导出不读取模型工作集或 React 当前分页;聊天窗口仍默认保留 3×32 条。
17
18 Markdown, JSON, clipboard and visual blocks share `internal/sessionexport`.
19 Tool results are associated across the entire snapshot by call ID using disk
20 staging. Markdown preserves output whitespace and uses collision-safe fences.
21 JSON retains `title`, `exportedAt`, `mcpList`, and `items`, adding snapshot metadata.
22 Persisted MCP display notices contribute attribution; observations absent from
23 older authoritative logs cannot be reconstructed and are explicitly scoped out.
24 The optional `diagnostic` event extension does not alter model input or require
25 an authoritative storage migration. The derived history index version is 10.
26
27 Markdown、JSON、复制全部和视觉语义块共享 `internal/sessionexport`。
28 工具结果通过 call ID 在整个快照内匹配,临时内容写盘;Markdown 保留原始空白,
29 围栏长度避开正文反引号。JSON 保留已有顶层字段并增加快照信息。
30 新增 MCP 展示通知通过可选诊断事件持久化并参与完整归因统计;旧日志从未保存的
31 通知无法恢复,导出元数据明确说明此范围。不改变模型输入,不迁移权威存储;
32 仅派生历史索引升级至版本 10。
33
34 ## Host and remote API / 宿主与远程接口
35
36 `BeginSessionExportForTarget`, `ReadSessionExportChunk`,
37 `AppendSessionExportPage`, `FinishSessionExport`, and `CancelSessionExport`
38 operate on a Desktop-owned handle. Exports survive component disposal. Source
39 validation rejects deletion/replacement rather than rebinding to an active tab.
40 Remote peers advertise `session-export-v1`; snapshot/document/validation/diagnostic
41 requests retain the expected-session fence. Remote snapshots are stateless: each
42 response releases its temporary files, so there is no remote lease to abandon.
43 Old peers fail explicitly without a last-page fallback. Existing Markdown and
44 goal-diagnostic entry points remain compatibility paths.
45
46 上述五个宿主接口仅按导出句柄操作,切换或卸载会话组件不取消导出。
47 来源被删除或替换时返回错误,不重新绑定活动标签。远程以
48 `session-export-v1` 协商能力,每个请求保留会话身份栅栏;远程快照无服务器租约,
49 临时文件随响应结束释放。旧服务明确提示升级,不退回导出尾页。
50 旧 Markdown 和目标诊断入口保留兼容路径。
51
52 ## Rendering and publication / 渲染与发布
53
54 PDF/PNG rendering consumes semantic blocks with backpressure, retaining one
55 surface and one encoded page at a time. The host validates image encoding,
56 dimensions, upload order and complete pages. PDF image objects are streamed to
57 a temporary file before its page tree and cross-reference table are completed.
58 Single files are synced and atomically replaced. PNG batches use exclusive
59 hard links and a sibling publication journal; the next batch in that destination
60 recovers unfinished publications using inode witnesses, preserving user
61 replacements. Filesystems lacking hard-link publication fail safely. No external
62 image fetch or attachment archive is introduced.
63
64 PDF/PNG 按语义块逐页生成,宿主确认后释放当前画布和页面,不累计全会话 DOM
65 或图片数组。宿主验证图像格式、尺寸、上传顺序与页面完整性;PDF 逐页写图像对象,
66 最后补齐页树和索引。单文件同步后原子替换;多 PNG 使用独占硬链接发布和同目录
67 事务清单,下次向该目录导出时凭文件身份清理未完成输出,保留用户替换文件。
68 不支持硬链接的文件系统会明确失败。不新增外部图片下载或附件打包。
69
70 ## State and diagnostics / 状态与诊断
71
72 Cross-page tool observations carry execution evidence and a lazy result locator.
73 Missing or unreadable content never implies cancellation. Subscription disposal
74 remains separate from execution cancellation. Diagnostics retain the goal schema
75 and add source identity, snapshot boundaries, frontend binding/read observations
76 and bounded lifecycle traces (256 entries per session). Unknown cancellation
77 provenance remains unknown. Runtime observations and export boundaries have
78 separate timestamps/watermarks. Independent diagnostic read failures are recorded
79 as unavailable; destination write failures still fail the export.
80
81 跨页工具观察提供执行证据和按需读取的结果位置。正文未加载或读取失败不代表
82 执行被取消;订阅释放与任务取消入口分离。会话诊断保留旧目标诊断字段,增加来源、
83 快照、前端绑定/读取观察和每会话最多 256 条生命周期轨迹。无法核实的取消来源
84 保留 unknown。运行时观察与导出边界各自记录时间和水位;独立读取失败记为
85 unavailable,目标文件写入失败仍判定导出失败。
86
87 ### Provider failures / 模型请求失败
88
89 Failed/interrupted turns with diagnostic evidence save an optional
90 `diagnostic/provider` event in the same atomic commit as `turn/end`.
91 Successful turns do not persist these request observations or peer addresses.
92 If generating the optional diagnostic fails, it is omitted with a warning in
93 the log; required closure events and `turn/end` still commit.
94 The event contains the structured failure classification and up to 128 recent
95 request observations belonging to that turn, without free-form transport error
96 text or API response bodies. Both live and cold
97 diagnostic exports retain these events in `commits`; the top-level
98 `providerDiagnostics` still describes only the current controller lifetime.
99 An empty live buffer does not mean the historical request was never sent.
100
101 有诊断证据的失败/中断轮次会在与 `turn/end` 相同的原子提交中保存可选事件
102 `diagnostic/provider`,包含结构化的失败分类和该轮最近最多 128 次请求的观测,
103 不额外保存自由文本形式的传输异常或 API 响应正文。可选诊断生成失败时会记录警告并
104 省略该记录,必需的收尾事件和 `turn/end` 仍正常提交。运行中或冷会话的诊断导出均在 `commits`
105 保留这些事件;顶层 `providerDiagnostics` 仍仅代表当前控制器生命周期。
106 实时缓冲为空不代表历史请求没有发出。成功轮次不持久化这些请求观测或对端地址。
107
108 `dropped` counts observations evicted for this turn, including when all its
109 requests have been evicted. `truncated` marks incomplete evidence. Accounting
110 retains at most 128 turn summaries separately from the shared 128-request ring.
111 If accounting is no longer available, `dropped` is omitted and `truncated` is
112 true; older events missing these fields have unknown completeness. A zero
113 per-turn count does not include evictions belonging to other turns.
114
115 `dropped` 是本轮被淘汰的请求观测数,即使本轮请求全部被淘汰也会保留计数。
116 `truncated` 标记证据不完整。计数独立于共享的 128 条请求缓冲区,最多保留
117 128 个轮次摘要;计数信息已淘汰时省略 `dropped` 并设置 `truncated: true`。
118 旧事件缺少这些字段时完整性未知。本轮计数为零不代表其他轮次没有丢弃记录。
119
120 Observations include the request host/path, method and byte count, last observed
121 phase, connection reuse, negotiated HTTP protocol, dial/connected addresses,
122 timestamps, response status/body byte count and a recognized HTTP/2 error code.
123 `dialAddress` is the last dial attempt, while `remoteAddress` is the acquired
124 connection's peer; neither proves which upstream hop caused a failure.
125 URL userinfo/query/fragment, headers and request/response bodies are excluded.
126 Missing fields on older observations remain unknown. `requestBytes = -1` means
127 the request body length was unknown. These records do not change model input,
128 cache prefixes, transport selection or the single-attempt request policy.
129
130 观测记录请求主机/路径、方法和字节数、最后观察阶段、连接是否复用、协商的 HTTP
131 协议、拨号/已连接地址、时间戳、响应状态/正文字节数,以及已识别的 HTTP/2 错误码。
132 `dialAddress` 是最后一次拨号尝试,`remoteAddress` 是已取得连接的对端;两者均不能
133 单独证明故障来自哪一跳。不保存 URL 用户信息/查询参数/片段、请求头或请求/响应正文。
134 旧记录缺少的字段保持未知,`requestBytes = -1` 表示未知正文长度。
135 这些诊断不改变模型输入、缓存前缀、传输协议选择或单次请求策略。
136
137 Failure cleanup preserves `terminalStatus` and `failureDiagnostic` on local-only
138 recovery records. HTTP/2 transport errors use `kind: transport_protocol` and an
139 optional `transportCode`; reopened history retains the failure notice rather
140 than relabelling it as a cancelled turn.
141
142 失败收尾会保留本地恢复记录的 `terminalStatus` 与 `failureDiagnostic`。
143 HTTP/2 传输错误使用 `kind: transport_protocol` 和可选的 `transportCode`;
144 重新打开历史时仍显示失败信息,不再因收尾丢失字段而退回取消轮次提示。
145
146 | Contract / 契约 | Old data / 旧数据 | Current reader / 新读取器 | Previous reader / 旧读取器 |
147 | --- | --- | --- | --- |
148 | `diagnostic/provider` | No record; do not infer evidence / 无记录,不推断 | Export raw optional events / 导出可选事件 | Skip unknown optional event; retain terminal / 跳过未知可选事件,保留结束状态 |
149 | `transportCode`, observation fields / 观测字段 | Missing is unknown / 缺省为未知 | Decode optional fields / 读取可选字段 | Ignore additive JSON fields / 忽略新增 JSON 字段 |
150 | Recovery metadata / 恢复元数据 | Existing fields remain readable / 原字段可读 | Preserve through cleanup / 收尾保留 | Existing format; an older writer may still strip it / 格式不变,旧写入器仍可能丢弃 |
151
152 ## Verification / 验证
153
154 Relevant commands:
155
156 ```sh
157 go test ./...
158 (cd desktop && go test ./...)
159 go test -race ./internal/session ./internal/control -run 'Test(FlushThrough|ExportSnapshot|StreamExportCommits|ToolObservation|SessionLifecycle|MCPAttribution|SessionDiagnostics|.*GoalDiagnostic|.*CancelSession)'
160 (cd desktop && go run . -emit-contract frontend/src/generated)
161 go run ./tools/desktopinventory
162 pnpm --dir desktop/frontend test:typecheck
163 pnpm --dir desktop/frontend test:transcript
164 pnpm --dir desktop/frontend test:app-lifecycle
165 pnpm --dir desktop/frontend test:transcript-browser
166 pnpm --dir desktop/frontend test:session-export-browser
167 pnpm --dir desktop/frontend build
168 ```
169
170 Fixtures cover >96 records, 15 samplings/23 tools, large Chinese payloads,
171 whitespace/fences, fixed cuts, version updates/retractions, dialog-time source
172 switching, cancellation isolation, detached results, unsupported peers, corrupt
173 pages, collisions, publication recovery and bounded lifecycle buffers.
174 The visual probe produces 22 PDF raster pages and 6 PNGs while retaining one
175 surface. The 240/1000-turn Chromium reader/switch suite passes. Same-configuration
176 startup assets measure 2444.2 KiB versus 2442.2 KiB at the baseline; only the raw
177 aggregate budget is adjusted to 2444.9 KiB. Renderer/execution and detached tool-content readers stay lazy;
178 gzip, CSS, individual chunk and interaction budgets are unchanged.
179
180 合成用例覆盖超过 96 条记录、15 次采样与 23 次工具、大段中文、空白和嵌套围栏、
181 固定边界、消息更新/撤回、保存框期间切换、取消隔离、跨页读取、旧远程能力、损坏页面、
182 冲突与发布恢复。视觉探针生成 22 页 PDF 栅格页和 6 张 PNG,只保留一个排版区域;
183 240/1000 轮 Chromium 滚动和切换套件通过。同构建配置首屏资源由 2442.2 KiB
184 增至 2444.2 KiB,原始总量预算调整为 2444.9 KiB;导出执行和渲染仍懒加载,
185 gzip、CSS、单块和交互预算不变。
186
187 The isolated Electron renderer-to-Go export round trip is verified. The native
188 macOS save sheet was exercised through the accessibility controller: Cancel
189 returned no export handle; Save published a Markdown snapshot in a temporary
190 directory, whose contents were checked. This native smoke used an empty canonical
191 session; long-history rendering and dialog-time rebinding have separate browser
192 and deterministic host tests. Manual workspace-switch/notification acceptance
193 and Windows native dialog/filesystem behavior remain external verification gaps.
194 Browser checks do not stand in for those native gates.
195
196 隔离 Electron 环境的渲染器到 Go 导出调用已验证。通过原生辅助功能通道验证了
197 macOS 保存框:取消不留下导出句柄,保存成功写入临时目录并核对 Markdown 内容。
198 原生冒烟使用空的权威会话;长历史渲染和保存期间来源切换分别由浏览器及确定性
199 宿主测试覆盖。原生工作区切换/完成通知的人工验收,以及 Windows 保存框和
200 文件系统行为,仍需相应实机或 CI 验证;浏览器结果不替代这些验收。
201
201 lines MARKDOWN