Skip to content

feat(modes): 用户可管理的对话模式 — 权限、确认与运行预算 - #4

Merged
Verlintas merged 8 commits into
Verlintas:mainfrom
fzcfweasdferttgg-png:custom-modes
Nov 6, 2026
Merged

Verlintas merged 8 commits into
Verlintas:mainfrom
fzcfweasdferttgg-png:custom-modes

Conversation

@fzcfweasdferttgg-png

@fzcfweasdferttgg-png fzcfweasdferttgg-png commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor
  • 设置新增「对话模式」页:可增删改模式,每模式包含工具权限(无/只读/完整)、逐调用确认、「长任务」、「完全同意」与运行预算(轮次/工具调用/时长)
  • 运行时按模式分级执行(CHAT / CHAT_PLUS / ACT / MAX),AgentLoop 按模式与预算执行 gate;「完全同意」下高危调用免确认,触碰设备即失效
  • 运行类别(Agent/Research/Chat)在创建时不可变记录到数据库(迁移 v22,旧记录按模式回填)
  • 任务页展示全部运行记录并按类别分组;状态筛选在 SQL 层执行
  • 「完全同意」与逐调用确认互斥,界面联动,并在保存与加载时归一
  • 聊天顶栏、会话与任务列表展示模式标签,聊天内可切换模式;删除模式时提示对话降为纯对话、运行记录保留
  • 附带修复:OpenAI 兼容端点的 API Key 改为可选(本地服务可无密钥)

模式改为可编辑的 ModeProfile:工具权限(无/只读/完全)、逐调用确认和运行预算均可在 设置→模式 中创建、修改、删除,内置模式同样可编辑或移除,可一键恢复默认。模式列表存储于 SharedPreferences(ModeProfileStore),会话、运行和计划任务记录模式 id;旧库中的枚举名即为内置 id,无需数据库迁移。引擎行为类(CHAT/CHAT_PLUS/ACT/MAX)由权限推导,预算经 budgetOverride 传入 AgentLoop。计划任务编辑器与模式选择器改为列出全部模式。
新增设置→模式→编辑器的独立全屏页面(导航路由,非拉伸弹窗):名称、工具权限、逐调用确认、「长任务」开关、模式专属指令(拼接到该模式的系统提示)、预算(预设+滑块)、重置为默认与删除(带确认与最少一个模式保护)。「长任务」开关将 MAX 的任务协议(计划、完成报告、结束横幅)与普通对话分离:自定义全权限模式默认关闭,不再在每次回答后弹出完成横幅;内置 MAX 默认开启。任务协议文本按开关选择,计划块与横幅同源受控。旧配置行自动沿用旧行为(仅 MAX 弹横幅)。
新模式开关「完全同意」(默认关):外部内容进入对话后,run_shell/manage_app 不再降级为确认,直接执行并在调用流中带「自动」标记;子任务继承该同意。范围仅限推荐的两项:模式自身的逐调用确认仍生效(独立开关),计划任务/自动化仍照旧拒绝无人值守的高危调用。

@Verlintas Verlintas left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

整体实现很完整。我在本地 worktree 跑了 test、lintDebug、assembleDebug、assembleRelease、许可证头、字符串同步和 tool schema,全部通过;fullConsent 的 gate 测试也覆盖了 unattended、ACT 确认和 autoConsent 标记,方向没问题。

建议先处理下面几项再合。

1. ChatScreen 里有一个字符错误(确定)

feature/chat/src/main/java/com/verlintas/baic2/feature/chat/ChatScreen.kt 第 1921/1925 行的 " В· " 用了 Cyrillic В(U+0412),不是中点 ·,界面上会显示成 В·。应改为 " · "。

2. fullConsent 和 requiresConfirmation 同时打开时语义冲突(确定)

编辑器允许两个开关同时打开,但 AgentLoop.gate() 里 fullConsent 只解除 taint 后的 HIGH 降级,mode.requiresConfirmation 仍然会返回 NeedsConfirm。UI 提示写的是“高危调用……不询问”,实际还会询问。

建议二选一:

  • 打开 fullConsent 时联动/强制关闭逐次确认,并加一条明确警告;
  • 或者保留组合,但 UI 明确写“仍需逐次确认”,不要写成不询问。

3. fullConsent 在聊天模式选择器里不可见(建议修)

ChatScreen.modeDescription() 对 stock 模式的判断只比较 toolAccess 和 requiresConfirmation,没有比较 fullConsent 和 isTask;自定义模式描述也只拼了“全部工具 · 免确认 · 长任务”,没有“完全同意”。结果是一个被编辑成 fullConsent 的 stock MAX,在聊天选择器里仍然显示普通 MAX 描述,顶部模式芯片也没有标记。

建议:

  • stock 描述判断加入 fullConsent / isTask;
  • 自定义描述加入 fullConsent;
  • 或在 Baic2ModeChip 上加一个明确的 full-consent 标记。

4. 定时任务模式与 Tasks 过滤不一致(需要确认)

ScheduledTaskEditor 现在列出全部模式(含 CHAT / READ_ONLY),ScheduledTaskRunner 也会为它们创建 Run;但 TasksViewModel 只保留 modes.resolve(run.mode).agentic(toolAccess == FULL)的运行。这样 READ_ONLY / CHAT 定时任务会跑,但 Tasks 里看不到对应 Run。

另外 RunDao.observeSummaries() 的 LIMIT 100 仍在分类过滤之前,历史非 agentic 运行多了可能把 agentic 运行挤出列表。

建议二选一:

  • 编辑器只允许 agentic 模式;
  • 或 Tasks 同时展示 read-only / chat 运行并分组;
  • 过滤尽量下推到 SQL,或把 limit 放到过滤之后。

5. 删除模式只提醒定时任务,不提醒会话/历史 Run(需要确认)

ModeProfilesPage 只检查 tasks.any { it.mode == mode.id };ModeProfileStore.delete() 不更新会话或 Run。删除后 resolve() 回退到 CHAT,历史 Run 会在 Tasks 里被 agentic 过滤掉,会话降级为普通聊天。

建议删除确认里补上会话/历史运行的影响,或给 Run 存一个不可变的 agentic/category 字段。

6. 子代理继承 fullConsent(需要决定)

SpawnAgentTool 把 fullConsent = run.fullConsent 传给子代理,子代理的 confirmationGate 固定返回 false。因此 MAX + fullConsent 的父运行可以 spawn 一个 MAX 子代理,子代理在 tainted 后直接跑 HIGH 工具。

如果这是有意的,建议在 UI/文档写清“完全同意包括子代理”;如果不是,建议默认不继承,或只在显式开关下继承。

小问题

  • .github/workflows/build.yml 上传 debug APK 可以加 retention-days: 7,避免 70MB artifact 长期堆积;文件末尾缺换行。
  • ModeProfileStore.read() JSON 损坏时会静默回退到 stock,自定义模式丢失;至少 log 一次。

已验证

  • test / lintDebug / assembleDebug / assembleRelease 通过
  • check-license-headers / check-strings-sync / check-tool-schemas 通过
  • ModeProfileTest、AgentLoopTest 的 fullConsent 用例通过
  • OpenAiCompatibleProviderTest 的空 API Key 用例通过
  • 这些结果只代表构建和单测;OS 端 UI 交互和真机 fullConsent 行为还需要手动验收

@Verlintas Verlintas left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

上一轮的 blocking 项都已处理并验证通过:

  • В· 已改为 ·
  • fullConsent 与逐次确认改为互斥,旧配置在读取时归一化
  • 模式描述/自定义描述补充 fullConsent 与长任务
  • Run.toolAccess 不可变落库 + DB 21→22 迁移,Tasks 按代理/研究/对话分组,状态过滤下推 SQL
  • 删除模式提示补充会话与历史运行的影响
  • 子代理继承 fullConsent 已在设置提示中明确说明
  • ModeProfileStore 损坏日志、CI artifact 撤回

本地 test / lintDebug / assembleDebug / assembleRelease / 许可证 / 字符串 / schema 均通过,CI build 通过;21→22 迁移 SQL 已用 21.json 建库模拟验证。

还有一个小的一致性问题:fullConsent 开启时 confirm 开关仍可打开,界面显示开但保存会被强制写回 false。不阻塞合并,我会在合并后直接在 main 上修。

@Verlintas
Verlintas merged commit 2880262 into Verlintas:main Nov 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants