Files
notebook-ai-extension/docs/superpowers/specs/2026-07-23-cell-toolbar-actions-v2-design.md
T

5.2 KiB

Cell Toolbar Actions v2 — 单按钮 + inline 输入框 + 删除 mode

  • 日期: 2026-07-23
  • 状态: 已批准(用户于 2026-07-23 确认)
  • 取代: v1(2026-07-23-cell-toolbar-actions-design.md,commit 9e7c36e)。本轮是 v1 的演进。

背景:v1 → v2

v1 把 ✨ 优化 / 🐛 排错 / 🪄 编辑 三个按钮从 cell 底部 footer 迁到原生 cell toolbar。用户反馈 4 个问题,本轮一并解决:

  1. Settings 不生效 —— v1 只在 settingRegistry.load(...).then(...) 调一次 setOpenCodeRuntime,没订阅 settings.changed,Settings Editor 改了值后模块级 _settings 仍是旧的。
  2. 单元格高度被压 —— v1 三个文字按钮让原生 cell toolbar 变高,把 code 编辑区挤小。
  3. 三个按钮合并为一个 —— 用户选 "完全合并为一个动作(按输入语义判断)"。
  4. 点击后 cell 内显示输入框 —— design.md v1 留的 inline prompt box,本轮实现。

同时用户给出两个架构边界(必须遵守):

  • 前端调用后端时,只获取 cell 的 input/output/error,不做任何处理(不决策 mode、不解析语义)
  • 1 notebook → 1 session(SessionManager 已保证,本轮不动)

决策

维度 决策
按钮 单个图标按钮(🪄)
交互 点击 → cell 内 inline 输入框(textarea + 🚀 发送 + ✕ 取消)
mode 概念 彻底删除。前端 request body 不再包含 mode;服务端 EditHandler 不再读 mode,响应体也不再回 mode;MODE_SYSTEM_PROMPTS 字典删除
服务端系统提示词 唯一一条统一提示词,LLM 根据用户自然语言 + context(含 traceback)自己判断优化/排错/编辑
成功时 前端 cell.model.sharedModel.setSource(resp.finalSource) 就地替换 cell 源码 + Notification
Settings 实时生效 index.ts 订阅 settings.changed → 重灌 setOpenCodeRuntime
providerId / modelId 仍从 JupyterLab settings 读 → 透传(用户配置,非"对 cell 数据的处理",保留)
作用范围 CodeCell;非 CodeCell → factory 返回空 Widget
之前的 footer 已删(v1)

接口契约

Request POST /opencode-bridge/edit:

{
  "prompt": "用户在 inline 输入框里写的自然语言指令",
  "context": {
    "notebookPath": "analysis/demo.ipynb",
    "cellId": "cell-3",
    "language": "python",
    "cellIndex": 3,
    "totalCells": 5,
    "source": "import matplotlib...",
    "previousCode": "import pandas as pd",
    "error": null
  },
  "providerId": "anthropic",
  "modelId": "claude-sonnet-4-20250514"
}
  • mode 字段
  • context.error 非空时,服务端在 OpenCode parts 里自动加 <traceback> 段(原 _build_request_body 行为,保留)
  • <instruction> 段:只要 prompt 非空就加(原条件 mode == "edit" 守卫删除)

Response:

{ "ok": true, "finalSource": "import plotly...", "sessionId": "ses-abc", "notebookPath": "analysis/demo.ipynb" }
  • mode 字段

系统提示词(统一,常量):

你是一个代码编辑助手。基于提供的代码上下文(以及 traceback,如果有),按照用户的指令修改代码。返回只包含修改后完整代码的回复,不要任何解释或 markdown 围栏。

(刻意保留 v1 'edit' 提示词的核心子串 "你是一个代码编辑助手",以便 test_edit_handler 的既有断言继续通过 —— 该测试只断言子串存在,不强耦合具体措辞。)

机制边界确认

  • 前端:OpenCodeCellActions(toolbar 里的单图标)+ OpenCodeInlinePrompt(cell 内的输入框 widget,Widget.attachcell.node)。组件代码只做:渲染按钮 / 显示输入框 / 取 cell.model.sharedModel.getSource() / 取 outputs / 取 error / 拼 context / POST / 成功调 setSource / 失败 Notification。做 mode 决策、做语义判断、管 session。
  • 服务端:拥有 SessionManager(1 notebook 1 sid,不动);EditHandler 唯一拥有的 "决策" 是 "是否包含 traceback"(由 context.error 决定,机械规则不算"处理");系统提示词选择(从前端决定的 mode 改为服务端的常量);调用 OpenCode Serve。Session 失效(404/not found)时 invalidate,前端重发。
  • OpenCode Serve:按系统提示词 + 上下文 + 用户指令干活,自己判断优化/排错/编辑。

兼容性

  • 后端 mode 字段(若调用方仍发)被忽略,不影响响应(为旧 API 兜底)。MODE_SYSTEM_PROMPTS 删除后,'optimize''fix' 提示词从默认路径不可达 —— 这是有意的(用户选择 "完全合并")。若以后需要可走专门 API。
  • 前端 OpenCodeMode 类型别名删除;OpenCodeRequest.mode 字段删除;OpenCodeSuccess.mode 字段删除。引用了这些的测试 / 组件同步更新。

验证

  • pytest opencode_bridge/tests/ 全过(含 test_edit_handler,改写后)
  • jlpm test 全过(单测重写 opencode_cell_actions.spec.ts,opencode_client.spec.ts 去掉 mode)
  • jlpm build 成功
  • 手动:jupyter lab 打开 notebook,active cell 右上角出现单个 🪄 图标;点击 → cell 底部出现输入框(带 placeholder、无默认值);输入指令 → 发送 → cell 源码被替换;切 cell 按钮随之移动