docs: expand simplification RFC implementation plans

This commit is contained in:
Tianyi Cui
2026-07-19 10:59:23 +08:00
parent 76db4efe49
commit 8941600273
6 changed files with 36 additions and 4 deletions

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
2026-07-19-make-jsonrpc-directional.md: 4531cb251c4d12c9f2d700c9297bdee87e284779
2026-07-19-make-jsonrpc-directional.zh.md: fb9bd06a9817357112b1eba2f41130ce2368d0b9
2026-07-19-make-jsonrpc-directional.md: 2a9579c53c111887e9d93cf02cc832304a496795
2026-07-19-make-jsonrpc-directional.zh.md: 4f3793f1b4de3b4f69c4219c10fe5b3b360c8692

View File

@@ -18,6 +18,14 @@ Specialize each endpoint to its actual role. The TypeScript transport will retai
Return the settled outcome directly from `session/prompt` as `{ status, reason }` after `agent.whenIdle()`. Delete `session.finished`, the constant acceptance response, and the Python post-response completion loop. `session.event` and subagent notifications still stream before the response, and durable session events remain the source for final-response reconstruction.
## Implementation plan
1. In `packages/ui/jsonrpc/src/server.ts`, replace `SessionPromptResult.accepted` with `status: 'ok' | 'error' | 'aborted'` and the captured `TurnEndReason`. `HarnessSdkServer.prompt()` will return `completed` as `ok`, `aborted` as `aborted`, and every other current or merge-extensible reason as `error`; reaching idle without a `turn/end` remains an invariant error. Remove only `session.finished`, leaving `session.event`, `subagent.started`, and `subagent.finished` unchanged.
2. In `packages/ui/jsonrpc/src/transport.ts`, replace `JsonRpcTransportPeer` with a server-side notification surface and retain `onRequest()`, `notify()`, `start()`, `flush()`, and `close()`. Remove generated request IDs, the pending-response map, outbound `request()`, inbound response and notification dispatch, and close-time pending-request rejection. Incoming response- and notification-shaped frames will be ignored, while request result, method-not-found, and handler-error responses retain their current behavior and remain ordered after notifications emitted by the awaited handler.
3. In `python/sdk/src/deepseek_harness/client.py`, `models.py`, and `__init__.py`, remove `IncomingRequest`, `_requests`, `notify()`, `next_request()`, `respond()`, and `respond_error()`. Add a public validated `SessionPromptResponse` carrying status and reason, return it from `session_prompt()`, and keep an explicit reader guard that ignores unexpected server-request frames instead of allowing them to match a response waiter.
4. In `python/sdk/src/deepseek_harness/api.py`, build `TurnResult.status` and a new `TurnResult.reason` from `SessionPromptResponse`, then delete the `session.finished` branch and second completion loop. Keep the subscription open during the request and preserve `_request_raw()`'s final notification drain so the last `turn/end` event and any subagent notification written before the response are collected before `Session.run()` reconstructs the final assistant message.
5. Replace the symmetric transport-pair cases in `packages/ui/jsonrpc/tests/transport.spec.ts` with raw client-input/server-output coverage, and update `server.spec.ts`, `plugin-apply.spec.ts`, and `built-scope-carrier.e2e.ts` for direct outcomes, ordering, overlap, shutdown, and the narrowed fake. Update `python/sdk/tests/test_client.py` for response-based settlement, unexpected-request-frame handling, callback and concurrency behavior, and the removed public helpers. Update the JSON-RPC and bilingual Python SDK READMEs, export JSDoc and declarations, `scripts/smoke-python-runtime.py`, and the Python single-executable snapshot.
## Alternatives considered
**Keep a generic symmetric JSON-RPC peer for future methods.** Server-initiated requests may eventually support interactive permissions, but no typed method or production consumer exists. The pre-release protocol can add the smallest required direction when that feature is designed instead of carrying an unexercised peer today.

View File

@@ -18,6 +18,14 @@ JSON-RPC 桥接层把两个端点都建模为对称的对等端,但实际协
`agent.whenIdle()` 完成后,由 `session/prompt` 直接返回 `{ status, reason }` 作为轮次结果。删除 `session.finished`、常量接纳响应以及 Python 中响应后的完成等待循环。`session.event` 与 subagent 通知仍在响应前流式发出,持久会话事件仍是最终响应重建的真源。
## 实施计划
1.`packages/ui/jsonrpc/src/server.ts` 中,用 `status: 'ok' | 'error' | 'aborted'` 和捕获的 `TurnEndReason` 替换 `SessionPromptResult.accepted``HarnessSdkServer.prompt()``completed` 映射为 `ok`,把 `aborted` 映射为 `aborted`,把其他当前或可合并扩展的原因映射为 `error`;进入空闲状态却没有 `turn/end` 仍视为不变量错误。只删除 `session.finished`,保持 `session.event``subagent.started``subagent.finished` 不变。
2.`packages/ui/jsonrpc/src/transport.ts` 中,用服务端通知接口替换 `JsonRpcTransportPeer`,并保留 `onRequest()``notify()``start()``flush()``close()`。删除生成的请求 ID、待处理响应表、出站 `request()`、入站响应与通知分发,以及关闭时对待处理请求的拒绝逻辑。入站响应结构和通知结构将被忽略;请求结果、方法不存在与处理器错误响应保持原有行为,并继续排在被等待处理器发出的通知之后。
3.`python/sdk/src/deepseek_harness/client.py``models.py``__init__.py` 中,删除 `IncomingRequest``_requests``notify()``next_request()``respond()``respond_error()`。新增公开且经过校验的 `SessionPromptResponse` 来携带状态与原因,由 `session_prompt()` 返回该对象,并保留明确的读取保护:忽略意外的服务端请求帧,避免它们命中响应等待器。
4.`python/sdk/src/deepseek_harness/api.py` 中,根据 `SessionPromptResponse` 构造 `TurnResult.status` 和新增的 `TurnResult.reason`,再删除 `session.finished` 分支与第二个完成循环。请求期间保持订阅打开,并保留 `_request_raw()` 最后的通知排空步骤,确保写在响应前的最后一条 `turn/end` 事件与任何 subagent 通知,都会在 `Session.run()` 重建最终助手消息之前被收集。
5. 用原始客户端输入与服务端输出覆盖替换 `packages/ui/jsonrpc/tests/transport.spec.ts` 中的对称传输对用例,并更新 `server.spec.ts``plugin-apply.spec.ts``built-scope-carrier.e2e.ts`,覆盖直接结果、顺序、重叠、关闭和收窄后的伪实现。更新 `python/sdk/tests/test_client.py`,覆盖基于响应的结束流程、意外请求帧处理、回调与并发行为,以及已删除的公开辅助方法。同步更新 JSON-RPC README、双语 Python SDK README、导出 JSDoc 与声明、`scripts/smoke-python-runtime.py` 和 Python 单可执行文件快照。
## 备选方案
**为未来方法保留通用的对称 JSON-RPC 对等端。** 服务端发起的请求将来可能用于交互式权限,但当前没有类型化方法或生产消费方。该功能完成设计后,预发布协议可以增加所需的最小方向,无需提前保留未使用的对等端能力。

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
2026-07-19-use-one-session-surface-manager.md: f351c05cf5cb5d408aeb22c8c3e6ac5c575fc24a
2026-07-19-use-one-session-surface-manager.zh.md: 20c1f04f7b4197549f23145aa2c6015cd44f38cc
2026-07-19-use-one-session-surface-manager.md: 0e4fa14b21f5054e1ace425712506c5c060f2251
2026-07-19-use-one-session-surface-manager.zh.md: 26126310eefaf56aa45efc428a54e65f0cf35947

View File

@@ -16,6 +16,14 @@ Keep one `SurfaceManager` per `Session`. Seed and append acceptance continue to
Expose only the readonly surface contract from `Session.surface`; candidate validation remains owned by `Session`. Retain `foldSurface()` as the detached full-log replay function used by offline validation and reconstruction.
## Implementation plan
1. In `packages/core/session/src/surface.ts`, export a structural `SessionSurface` contract containing only readonly `nodes` and `replaceGeneration`, and make `SurfaceManager` implement it. Re-export that type from `packages/core/session/src/index.ts` so `Session.surface` no longer exposes `validateNext()` through its declaration.
2. In `Session`, replace `surfaceValidator` and lazy `_surface` with one eagerly constructed `surfaceManager`. Route seed and append validation through that manager and return it from `get surface(): SessionSurface`; `deriveMessages()` will read the same nodes and generation. `validateNext()` may synchronize already committed log entries, but it must only plan the uncommitted candidate. The candidate reaches manager state after `log.push()` and the next delta synchronization, so rejection by surface validation or pre-commit `internal/dispatch` cannot leave phantom state.
3. Keep `foldSurface()` and the transition functions in `surface.ts` unchanged. Compile and exercise the direct consumers in `packages/compact/compact/src/tool-pairing.ts`, `packages/compact/compact-basic/src/region.ts`, and `packages/context/workspace-context/src/state.ts`; they continue to consume only nodes and replacement generation.
4. Extend `packages/core/session/tests/surface.spec.ts` to read the public view before an invalid candidate, prove that nodes and generation remain at the accepted prefix after rejection, append a later valid event, and compare every resulting prefix with `foldSurface()`. Add an `internal/dispatch` veto case and a type-level `SessionSurface` assertion in `session.spec.ts`, while retaining the seeded replay, delta-growth, replacement, generation, and derived-cache cases.
5. Run the request-reconstruction, compaction tool-pairing, compaction range, and workspace-context regression suites that consume the surface. In the implementation PR, update `packages/core/session/README.md`, `docs/core-data-structures/session.md`, the implemented session-surface RFC and its Chinese counterpart, the translation record, `scripts/type-equiv.manifest.json`, and the generated RFC index before moving this RFC pair to `implemented/`.
## Alternatives considered
**Keep acceptance and projection state separate.** Separate instances appear to isolate public reads from validation, but ordinary callers already receive borrowed surface state and cannot mutate it through the declared readonly contract. A cast that mutates the returned node array already corrupts derived history; duplicating the manager is not a sound runtime trust boundary.

View File

@@ -16,6 +16,14 @@ Status: proposed
`Session.surface` 只公开只读表层契约,候选事件校验仍由 `Session` 负责。保留 `foldSurface()`,用于离线校验与重建时执行分离的完整日志回放。
## 实施计划
1.`packages/core/session/src/surface.ts` 中,导出结构化的 `SessionSurface` 契约,只包含只读的 `nodes``replaceGeneration`,并让 `SurfaceManager` 实现该契约。从 `packages/core/session/src/index.ts` 重新导出这个类型,使 `Session.surface` 的声明不再暴露 `validateNext()`
2.`Session` 中,用一个主动创建的 `surfaceManager` 替换 `surfaceValidator` 与延迟创建的 `_surface`。种子事件与追加事件都通过该管理器校验,`get surface(): SessionSurface` 返回同一个对象,`deriveMessages()` 也读取同一份节点与代数。`validateNext()` 可以同步已提交的日志事件,但对尚未提交的候选事件只能制定变更计划。候选事件在 `log.push()` 之后、下一次增量同步时才进入管理器状态,因此表层校验拒绝或提交前 `internal/dispatch` 否决都不会留下虚假状态。
3. 保持 `foldSurface()``surface.ts` 中的状态转换函数不变。编译并验证 `packages/compact/compact/src/tool-pairing.ts``packages/compact/compact-basic/src/region.ts``packages/context/workspace-context/src/state.ts` 中的直接消费方;它们仍然只读取节点与替换代数。
4. 扩展 `packages/core/session/tests/surface.spec.ts`:先读取公共视图,再提交无效候选事件,证明拒绝后节点与代数仍停留在已接纳前缀;随后追加有效事件,并把每个结果前缀与 `foldSurface()` 比较。在 `session.spec.ts` 中新增 `internal/dispatch` 否决用例与类型层面的 `SessionSurface` 断言,同时保留种子回放、增量增长、替换、代数和派生缓存用例。
5. 运行消费表层的请求重建、压缩工具配对、压缩范围与工作区上下文回归套件。在实现 PR 中,先更新 `packages/core/session/README.md``docs/core-data-structures/session.md`、已实现会话表层 RFC 及其中文对应文件、翻译记录、`scripts/type-equiv.manifest.json` 和生成的 RFC 索引,再把本 RFC 双语文件移入 `implemented/`
## 备选方案
**继续分离接纳状态与投影视图。** 两个独立实例看似能够隔离公共读取和校验,但普通调用方目前取得的就是借用的表层状态,无法通过声明的只读契约修改它。通过类型断言修改返回的节点数组,本就会破坏派生历史;复制管理器并不能构成可靠的运行时信任边界。