Repository navigation
Conversation
AI Code Review审查结论不通过 本次变更仅新增 计划符合性:文档结构与同目录既有设计文档(01/02)风格一致,背景、架构、DSHAgent/DSHProcess、插件、调研章节齐全,绝大多数框架 API 声称与真实源码吻合( 主要风险:发现两处高置信设计缺陷——① 文档核心的会话 JSONL 持久化机制( 测试影响:本变更无测试(纯文档),上述设计问题无法由测试捕获;文档中提供的 Python 示例代码( 门禁结论:FAILED。两处问题均锚定在变更引入的设计契约上,属于高置信、可操作的设计缺陷,建议合入前修正文档中的持久化写回方式(改为在 yield 的最终事件上携带 state_delta 或在 发现的问题严重
问题: 触发条件: 任何一次 实际影响: 按文档实现后,每轮生成的 修正方向: 将写回动作改为可被框架持久化的形式:在 中等
问题: 文档定义的两个对端协议结构字段命名不一致且未声明任何映射:Python 侧 触发条件: DSHAgent 把 实际影响: 每轮的 修正方向: 在文档中明确定义 |
| finally: | ||
| # 正常结束和被取消都写回;取消时包含 partial 输出 | ||
| ctx.actions.state_delta[DSH_SESSION_STATE_KEY] = self._state_store.state_delta(state) |
There was a problem hiding this comment.
问题: _run_async_impl 的 finally 块(404-419 行)把本轮 JSONL 只写入 ctx.actions.state_delta[DSH_SESSION_STATE_KEY],但框架中 ctx.actions.state_delta(即 ctx.event_actions.state_delta)只在事件被 session_service.append_event() 追加时才会随事件持久化。已核对仓库源码:runner.py 仅对 async for event in current_agent.run_async(...) 产出的非 partial Event 调用 append_event(runners.py:539),base_session_service.py:94-106 只在该事件被追加时把 event.actions.state_delta 并入 session.state;而 _run_async_impl 生成器结束后没有任何代码再读取 ctx.actions.state_delta(BaseAgent.run_async 的 finally 只做 trace;Runner 仅在 RunCancelledException 分支调 update_session,且不携带 ctx.actions)。DSH_SESSION_STATE_KEY 的写入发生在最后一个事件已 yield 之后,因此既不随事件落库,也无单独持久化调用。
触发条件: 任何一次 runner.run_async() 调用 DSHAgent 时都会发生:成功路径上最后一轮 session.status idle 不被 to_trpc_event 转成 Event(不产生任何后续追加),取消路径上 raise_if_cancelled() 抛 RunCancelledException 后由 Runner 兜底清理,同样不读取 ctx.actions.state_delta。
实际影响: 按文档实现后,每轮生成的 { jsonl, version }(即整个 dsh 会话历史快照)永远不会写入 SessionService.state,下一轮 _state_store.load(ctx.session) 读到的始终是空状态;DSHAgent 的跨轮会话记忆、取消时的 partial 输出保留以及 session/trpc-prompt 回传 JSONL 的能力全部失效,这是该设计第 2/3 章的核心机制。
修正方向: 将写回动作改为可被框架持久化的形式:在 _run_async_impl yield 的最后一个非 partial Event(或新增一个收尾 Event)的 event.actions.state_delta[DSH_SESSION_STATE_KEY] 上附带该值;或在生成器结束前显式调用 await ctx.session_service.update_session_state(ctx.session, {DSH_SESSION_STATE_KEY: ...})(该接口已存在于 abc/_session_service.py:128,默认实现桥接 update_session)。文档应写明选定的路径并删除对 ctx.actions.state_delta 直接写入的依赖。
| @dataclass(frozen=True) | ||
| class DSHModelSpec: | ||
| provider: str | ||
| model: str | ||
| reasoning_effort: str | None = None | ||
| max_tokens: int | None = None |
There was a problem hiding this comment.
问题: 文档定义的两个对端协议结构字段命名不一致且未声明任何映射:Python 侧 DSHModelSpec(563-568 行)使用 snake_case reasoning_effort / max_tokens,而 JS 侧线协议 TrpcPromptRequest.model(756 行)声明的是 camelCase reasoningEffort? / maxTokens?。同一文档既是 Python 实现契约又是 JS trpc-jsonrpc-server 契约,JSON-RPC 参数按序列化结果原样传递,文档未说明 DSHModelSpec → JSON 的字段转换规则。
触发条件: DSHAgent 把 model=OpenAIModel(...) 转成 DSHModelSpec 后随每轮 session/trpc-prompt 发送时(243、653 行描述的行为);若 Python 侧按 dataclass 字段名直接序列化,reasoning_effort/max_tokens 将以 snake_case 到达 JS 侧,而 TrpcPromptRequest/解析侧按 camelCase 读取。
实际影响: 每轮的 reasoningEffort/maxTokens 模型参数会被 JS 侧静默忽略(读不到对应 key),或按未知字段剔除/报错;而 provider/model 因两处同名单字段不受影响,问题不易被察觉,最终表现为 dsh 侧推理力度与最大 token 上限失效。
修正方向: 在文档中明确定义 DSHModelSpec 的序列化规则:要么在 Python 侧序列化时显式转换字段名为 reasoningEffort/maxTokens(与 JS 接口一致),要么统一两侧命名并在 TrpcPromptRequest 注释中声明 alias。建议以 JS 线协议(camelCase)为基准,并在 DSHModelSpec 后补充一行说明。
No description provided.