openheron
第 6 章

界面怎么用

元素 作用
侧边栏 会话列表、Agent 过滤、状态点(有待审批时会亮)
输入框 提问;/ 开头触发斜杠命令;支持拖拽/粘贴附件
消息列表 助手回复、思考过程、工具调用卡片、子 Agent 产出(带归属)
审批卡 需要你点头时出现,同意 / 拒绝(可附理由)
工具卡 每个工具调用的参数与结果
设置 配置编辑器的入口

6.1 斜杠命令

命令 作用
/new 新建会话
/stop 停掉当前这轮
/attach 往当前会话附加文件
/settings 打开配置编辑器
/agents 切换当前会话的 Agent
/compact 立刻压缩当前对话 —— 见 §6.6
/skill 为这次任务指定一个技能
/review 复查当前改动或给定路径
/test 跑相关测试并汇总失败项
/explain 解释给定代码
/fix 定位根因并修掉给定问题

6.2 审批怎么走

当模型要调一个 ask 档的工具时:

  1. 运行暂停,界面出现审批卡片。
  2. 你选同意或拒绝;拒绝可以附一句理由。
  3. 决定被写回会话,模型收到结果继续。

★ 被拒绝时模型收到的是一句拒绝说明(带你的理由),不是一个错误。 所以它能据此换个做法,而不是直接崩掉。

★ 审批的恢复点存在会话里。如果那个恢复点丢了(比如会话目录被清理过), 界面会明确告诉你「这个审批已经无法恢复,发条新消息继续」,而不是静默新开一轮。

6.3 配置编辑器

/settings 打开。它能改:llm/ agents/ policy/ tools/。

写入有几道闸门:

  • server/ 不可编辑(不热重载,改了要重启)。
  • 密钥字面量被拒 —— api_key must be a reference, not a literal。 要用 ${ENV_VAR} 或 @file:/path。
  • 没有 YAML 内容的文件被拒 —— 纯空、或者只有注释的文件根本没有配置。报错会点名 这个文件需要哪些字段;在 tools/ 下还会说清是哪个工具缺了什么。
  • 乐观并发:如果文件在别处被改过,保存会报冲突,让你选覆盖还是放弃。

6.4 上下文仪表盘

输入框下面那一行的末尾,是你正在对话的那个 agent 的上下文占用:

Agent: main · deepseek/deepseek-flash · Reasoning: off · Context: ≈18k / 131k (14 %)
  • 那个数字是该 agent 最近一次请求的大小 —— 不是整段对话的总量。一段长对话可能花了很多, 上下文却还很空。
  • 它是厂商自己的计数,所以是估算:≈ 是故意写在那儿的。
  • 进度条到窗口的 80 % 变琥珀色,95 % 变红。
  • 模型没声明上下文窗口时,仪表盘只报 token 数(Context: ≈18k tokens),不报比例。 想看进度条,就在 llm/<vendor>.yaml 里写 context_window。

多个 agent 同时在场时,agent 过滤器里每个 agent 各有一个数字 —— 每个 agent 有自己的上下文, 而且大小通常不一样。

★ 占用与 agent 的花费是两个数。仪表盘讲的是上下文还剩多少空间;花费讲的是这一整段会话 里这个 agent 花了多少。

6.5 压缩分隔线

上下文被压缩时,对话里会出现一条分隔线(界面文案是英文):

────────────  12 earlier messages · compacted into a summary · ≈62k tokens saved  ────────────
  • 分隔线标的是模型读到哪里为止。它上面,agent 读的是一段摘要;那些消息本身不再发出去。
  • 消息仍然留在记录里、仍然读得到 —— 压缩缩短的是上下文,不是记录。往上滚,切口之前的 对话还在。
  • 数字是估算:≈62k 是厂商自己的 token 计数减去摘要的大小,说的是这一刀省下了多少空间。
  • 轮内发生的压缩会当场画出分隔线,但不带数字:数字是拿记录量出来的,而记录要等这一轮 结束才写。重新打开这个会话,数字就出来了。

★ 摘要本身不显示。它是模型的工作材料,不是你的对话 —— 而且被它顶替的那些消息还在屏幕上。

6.6 /compact —— 手动压缩

上下文到了 agent 的阈值会自己被压缩(见 §4.1)。/compact 做的事一样,只是由你开口: 它把对话总结成一段摘要,当场让那段摘要成为新的边界。

/compact
  • 它花一次模型调用 —— 摘要由 agent 自己的模型生成,与自动压缩走的是同一条路。
  • 它与阈值无关。自己不压缩的 agent(summarize_at: 0)照样能手动压:「关」说的是 「别自己压」,不是「不许压」。
  • 压完分隔线就出来了,带着数字。压的过程中,composer 上写着 Compacting the conversation…。
  • 分隔线上面的消息仍然读得到 —— 压缩缩短的是上下文,不是记录。

★ 上下文太小的时候它会拒绝。 摘要带着前言和你自己的话,短对话压完可能反而更长。 少于四条消息、或者上下文不到大约 4k token 时,/compact 会说没什么值得压的,然后什么也不做。

★ 轮次在跑、或者有审批在等的时候,它也会拒绝。 两者都占着上下文:在它们底下切一刀, 切的就是它们正在用的那份历史。先把轮次停掉。

同一件事也有 HTTP 入口 —— POST /v2/sessions/{id}/compact —— 脚本可以用。

6.7 同一个会话开两个窗口

一个会话同时只跑一轮。同一个会话开在两个窗口里 —— 两个标签页,或者一个标签页 加另一台机器 —— 那么只有一个能跑轮次。

另一个会告诉你:

This session is running in another window — stop it to take over

★ 什么都不会丢。 被拒的那条消息没有发出去,所以它不会出现在对话里。正在跑的 那一轮照跑,毫发无损。

★ 停止按钮就是接管的方式。 它停掉这个会话的轮次 —— 不管它属于谁 —— 然后你就 能发消息了。拥有那个轮次的窗口会看到它停下来。

★ 这是服务端的规矩,不是浏览器的。 任何跟接口说话的客户端都得到同样的答复; 会话的 state 对每个看它的客户端都报 "running"。在轮次运行期间打开的第二个 窗口,水合出来就是「忙」,发送按钮已经是禁用的。

★ 连接断了也不会丢掉这一轮。 轮次属于服务端,不属于碰巧在看着它的那条连接: 服务端照样归档。连接断掉的客户端带着 run 的 id 回来——POST /v2/run,带 runId、不带问题——就能拿到这一轮剩下的部分。GET /v2/sessions/{id}/runs 说这个 run 还跑不跑;它不跑的时候,那一轮的历史就在那里。