Files
apes-sidebar/docs/subagent-state-enumeration.md
T
figmar 35d33c7f65
CI / ci (pull_request) Canceled after 0s
CI / ci-windows (pull_request) Canceled after 0s
CI / plugin-mount (pull_request) Canceled after 0s
fix(subagent): hydrate the catalog via the host's refreshProjections
0.2.0-rc.2 withdrew every catalog/subagent seam this fork was written
against, and all three calls degraded to silent no-ops:

  openSubagent(address)             -> gone
  setSubagentCatalogOpen(id, open)  -> gone
  refreshSubagents(id)              -> gone

The host's own subagent UI (dsh-client-ui-subagent) rebuilds a parent's
child catalog with `sessions.refreshProjections(parentSessionId)`, so
that is the only kick that still exists. Wire it into `observe()` and the
catalog retry button, keeping the legacy names as fallbacks for older
hosts. Without it the root catalog never hydrated: the page sat on
"loading" or degraded to synthesized summary rows.

Also document what the investigation settled:
- docs/subagent-state-enumeration.md: the full state model (catalog
  child / diagnostic / session / job / sidechat) and proof that this
  fork already renders it 1:1 with upstream.
- docs/plugin-conventions.md: the hard rules another sidebar plugin
  must follow (host schemastery, volatile prefs, ns = profile entry id,
  no colons in tab ids, never read a volatile field directly) plus the
  withdrawn-API replacement table and a pre-release checklist.
- docs/feedback-0.2.0-rc2-contract-gaps.md: gaps 2/3 reframed. The ask
  is documenting the official paths (open(childSessionId) /
  refreshProjections(id)), not adding new APIs.

Gates: typecheck 0, lint 0, build 0, test 131 files / 1385 passed.
2026-10-13 23:18:30 +08:00

3.6 KiB
Raw Blame History

子 Agent 完整状态枚举(对齐 better-sidebar 原版)

口径来源:better-sidebar 原版 src/client/SubagentView.tsx + src/subagent-activity.ts(本 fork 完整保留) 宿主事实来源:@deepseek-ai/* 0.2.0-rc.2 真实包内代码 结论:本插件的状态渲染已 100% 对齐原版;枚举上限由宿主字段决定,不是插件缺口。

一、三个状态域 + 一个诊断分支

域 1:子代理 catalog 行(拓扑卡片)— 主战场

数据源:sessions.list.getSnapshot().subagentsByParent[parentId].entries[],其中 kind: 'child'。

字段 取值 渲染
activity 'running' | 'inactive' StateDot state='ongoing' | state='done'
mode 'one-shot' | 'continuable' 副行文本(一次性 / 可续)
hasChildren boolean 是否可展开(真叶子不给 aria-expanded)
label? string 主标签;缺省回退 summary.displayTitle,再回退 entry.id
id string 行标识 + address 组装

副行格式(原版 cardSecondary):displayTitle · mode · activity,空段跳过。

running 行额外显示实时活动:subagents.live 批量路由 → LastActivity { text?, tool?{name,args} } (服务端 lastActivity() 扫会话事件日志尾部的最后一条 assistant 文本 + 最后一次工具调用)。

域 2:catalog 行不可读 → 诊断分支

kind: 'diagnostic'(损坏 / 不受支持 / 不可用)→ StateDot state='error'。 容器级状态另有 SidebarSubagentCatalog.state: 'loading' | 'ready' | 'error',驱动空态行与重试按钮。

域 3:会话行(非拓扑列表)

SidebarSessionSummary.running?: boolean → StateDot state={running ? 'ongoing' : 'done'}。 注意:宿主对会话只给这一个布尔,没有更细的状态。

域 4:后台 job 与 SideChat

面 字段 取值 → dot
后台 job job.status running/stopping/completed/killed/failed → jobDotState()
SideChat 行 行级 failed / running error / ongoing

二、StateDot 的可用状态(宿主固定,插件改不了)

StateDot 来自 @deepseek-ai/dsh-client-ui-primitives,只有 3 个 state: 'ongoing'(活动)/ 'done'(静止)/ 'error'(失败)。

⇒ 插件能把 N 态数据映射到 3 个视觉态,仅此而已。要更细的视觉必须宿主开口子。

三、原版 vs 本 fork 对照(结论:已对齐)

面 原版 本 fork
activity → dot running ? 'ongoing' : 'done' 同
diagnostic → dot 'error' 同
副行 mode·activity cardSecondary 同
running 实时行 LastActivity 同
会话行 dot running ? 'ongoing' : 'done' 同
job dot jobDotState(status) 同
SideChat 失败行 'error' 同

四、宿主侧真实缺口(不是枚举本身,而是枚举的「上游」)

0.2.0-rc.2 里原版依赖的三个 API 全部消失(app 内 @deepseek-ai/* 全量 grep 0 命中):

原版调用 0.2.0-rc.2 状态 官方替代
sessions.openSubagent(address) 不存在 sessions.open(childSessionId)(切主面板;最终走 replaceMain → retain)
sessions.setSubagentCatalogOpen(id, open) 不存在 sessions.refreshProjections(id)
sessions.refreshSubagents(id) 不存在 同上

⇒ catalog 的来源(宿主 hydrate)曾长期缺失,这才是「恒加载中」与「点不进去」的真根因;枚举与渲染层面本插件无缺口。