Skip to content

Report only the sessions a user is driving, not the ones inside them - #7

Closed
CaffreySun wants to merge 1 commit into
dncore:mainfrom
CaffreySun:pr/panel-only-user-sessions
Closed

CaffreySun wants to merge 1 commit into
dncore:mainfrom
CaffreySun:pr/panel-only-user-sessions

Conversation

@CaffreySun

Copy link
Copy Markdown
Contributor

做了什么

面板上只显示用户自己启动的会话:

之前 之后
敲 omp 进交互界面 一行 一行(不变)
会话内部派的子代理 每个占一行,派几个多几行 不出现
omp -p / --mode json 画一行,几秒后消失 不出现

为什么一条规则就够

判据是扩展上下文里的 ctx.mode,不是子父关系。

omp 给子代理建扩展运行时用的是 initialize(actions, contextActions) —— 只有两个参数,没有 mode,于是子代理的 ctx.mode 取运行时的默认值 "print",即使它的父会话是交互式 TUI(实测 omp 18.3.0,pty 里真跑的一次:父 mode: "tui",子 mode: "print")。

所以在 mode 这根轴上,子代理和 omp -p 是同一种东西。一个判断同时管住两件事:

function isReportable(ctx) {
  try {
    const mode = ctx && ctx.mode;
    return mode !== "print" && mode !== "json";
  } catch {
    return true;
  }
}

两个设计选择:

  • 闸门放在 send() 里,不放某个 handler 里。report() 和 reportContext() 是它仅有的两个调用者,将来新加的 handler 不可能绕过去拿到 shim。
  • 点名沉默的那两种 mode,而不是列举活跃的。没见过的 mode 仍然上报 —— 多点一行看得见,静默了没人会发现。

实测

对着一个监听中的 UDS 跑:

  • omp -p:5 个信封 → 0 个
  • 交互式 TUI 会话里让模型派一个子代理:2 个 session id → 1 个(父会话 8 个事件不变)

两个代价(已写进 §8.8)

  1. 子代理干活期间,面板上看不到"还在忙"。 实测异步 spawn(async.enabled 默认 true):父会话 t=11.7s 发 agent_end,子代理最后的工具在 t=15.76s,父会话到 t=15.76s 才重新 agent_start —— 中间约 4 秒父行显示"已完成"。这和本项目为 Claude Code 记下的是同一类误报。要修得让 omp 侧发出 background_tasks 信号,它的 profile 目前不带这个字段。
  2. 只用 omp -p 的装机,管理窗口的卡片会显示 Degraded。 因为 lastEventAt 一直是 nil。进一次交互界面就变绿。

顺带修正的文档问题

  • docs/ARCHITECTURE.md §8.8 的真机验证配方原本让读者用 omp -p 证明集成可用 —— 现在那条命令一个信封都不发,照着跑会把好装机判成坏的。改成指向交互式运行,并给 §6.7b 的 Pi 配方(同样是 headless)加了同样警告。
  • §Claude Code 的 Stop 后台任务抑制 那样写连说一连 numbering —— 全文其余 70 处 § 都带编号,改成 §5.1b。
  • 原来写 background_tasks「只有 Grok 有」是错的:Claude Code 靠默认字段名 background_tasks 走同一条抑制路径,Grok 只是显式声明了 backgroundTasks。
  • 原来写 --json 这个 flag —— 它不存在,实测 omp --json 报 Error: unknown flag。正确写法是 --mode json。
  • ExtensionTemplate.swift:9 与 §8.8 表格是同一张表的两份副本,之前分别写着 Pi 0.85 与 0.87。§6.7b 那条带日期的 0.85.1 保留原样(它记的是当天核查的版本),另加一句说明表头的 0.87 是装机发行物的口径、不是行为重测。

测试

585 tests / 88 suites 全绿(原 583 + 新增 2)。

新增的两条测试用变异验证过:把生成器分别改成 &&→||、给 mode 加 || "print" 默认值、在 return 前插 typeof 守卫 —— 三种各让 2 条测试失败,改回后通过。(第一版的断言只查了两个 mode 名子串,对 || 也成立,等于把闸门改成失效而测试仍绿;这条是审查时发现的,已修。)

生效方式

改的是生成模板。要让已装应用用上,需对 omp(和 Pi)重新执行一次 Configure —— 扩展在会话启动时加载,还要新起一个会话。

A session spawned inside a session drew a row of its own, so a prompt that
fanned out drew as many rows as it had children (user report, 2026-09-24); and
`omp -p` drew one for the few seconds the run lasted, then took it away again.

The discriminator is `ctx.mode`, not the session tree. omp builds a subagent's
extension runner with `initialize(actions, contextActions)` — two arguments, no
mode — so `ctx.mode` takes the runner's default `"print"` whatever the parent
is: measured inside a real interactive TUI session, the parent's context reads
`mode: "tui"` and the child's `mode: "print"`. A subagent is therefore the same
shape as `omp -p`, and one test decides both. `send()` now returns before it
spawns when the mode is `"print"` or `"json"`.

`send`, not the handlers: `report()` and `reportContext()` are its only
callers, so a handler added later cannot reach the shim unguarded. The silent
modes are named rather than the loud ones listed, so a mode this file has never
heard of still reports — an extra row is visible, while a silent session is not.

Two costs, both recorded in §8.8:

- While a child works, nothing shows work. Measured with an async spawn
  (`async.enabled` defaults true): the parent's `agent_end` lands at t=11.7s,
  the child's last tool at t=15.76s, and the parent resumes only at t=15.76s —
  about four seconds in which the parent row reads "completed". The same
  mis-signal this project already records for Claude Code; suppressing it needs
  omp to send `background_tasks`, which its profile does not carry.
- An install used only through `-p` never sets `lastEventAt`, which reads as
  `.degraded` on the manager card.

`docs/ARCHITECTURE.md:1156` is the section's own verification recipe and told
the reader to prove the integration with `omp -p`; that command now yields zero
envelopes, so it points at an interactive run instead. The same warning is
added for §6.7b's Pi recipe, which is also headless. `ExtensionTemplate.swift:9`
and the §8.8 table are one table in two copies and were naming different Pi
versions; §6.7b's dated 0.85.1 entry stays, since it records what was checked
that day, and a note says the header's 0.87 is the installed distribution's
claim rather than a behavioural re-test.

Measured against a listening UDS: `omp -p` went from five envelopes to zero;
an interactive run carrying one subagent went from two session ids to one, with
the parent's eight events unchanged.

Checks: 585 tests in 88 suites, `--status` exit 0. The assertions were checked
by mutating the generator three ways — `&&` to `||`, a `|| "print"` default, and
a `typeof` guard ahead of the return — each failed two tests.

Co-Authored-By: Claude Code <[email protected]>
@dncore

dncore commented Sep 28, 2026

Copy link
Copy Markdown
Owner

合并为 7f7074b(cherry-pick,无 merge commit)。

复核时在合并后的树上核对,两处描述与树不符(代码本身没问题):

  • 三种变异各让 1 条测试失败(unknownModeFailsOpen),不是 2 条。
  • §6.7b 的 Pi 验收配方那里没有加上警告,警告只在 §8.8 里点名了它;已补在该节本处,另开一个提交 f6a5802。

判据在另一侧独立核对过(omp 18.3.5 源码):ExtensionMode = "tui" | "rpc" | "json" | "print"、runner 的默认 #mode: ExtensionMode = "print"、TUI 控制器传 "tui"、RPC 与 ACP 传 "rpc"、print/JSON 传 "print"/"json",以及 src/task/executor.ts 里子代理那个 initialize(actions, contextActions) 两参调用。生成的扩展用假宿主驱动跑过一遍:tui / rpc / 未知 mode / 无 mode 全部上报,print / json 一个都不 spawn(含 context_update)。

@dncore dncore closed this Sep 28, 2026
@CaffreySun
CaffreySun deleted the pr/panel-only-user-sessions branch September 28, 2026 03:30
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