Files
HomeAgent/internal/sdk/status.go
JianFeeeee e4d69fa140 feat(webui): 总览改版 —— 阶段管道滑块 / per-agent 负载环 / 通道→agent 拓扑与光点
总览页此前是一堆数字与文字块,看不出「这一轮走到哪、谁忙、消息从哪进哪出」。
本次把运行态面板改成以图形为主:

- 阶段管道:七阶段滑块,由 SSE stage 事件驱动,当前阶段高亮、滑块滑过去;
  一轮结束(after_output 或 2.5s 无事件)自动回到空闲,不做假动画。
- 队列与中断栈:沿用五条进度条(L1–L4 + 排队),中断栈补一条深度进度条。
- Agent 拓扑:改成「每 agent 一条横带」——左 inputch、中 agent 节点(圆环 = 负载)、
  右 outputch,连线即路由;删掉旧的「归属框 + 单个内核盒」画法(看得出哪个子接了哪条输入)。
- 光点动画:channel_input(新增轻量 SSE 事件)沿 inputch→agent 连线跑;
  agent_output 沿 agent→outputch 连线跑。用 SMIL animateMotion,不需要 rAF 循环。
- 负载:由该 agent **自己的**调度器积压(排队 / 四级中断 / 中断栈)按级别加权折算,
  环形图展示。为此把驻留子的调度器积压透出到状态面(SDK 纯追加字段)。

后端:sdk.ResidentStatus / core.ResidentInfo 增加子 agent 调度器积压四项;
WebUI SSE 增加 channel_input 轻量事件(只带通道名与 agent id,不带正文)。

顺带收口对话区视觉(页签改分段控件、消息间距/气泡区分、输入区分隔线)。
2026-09-14 15:33:23 +08:00

260 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package sdk
// StatusAPI provides a snapshot of the kernel runtime status.
type StatusAPI interface {
GetKernelStatus() *KernelStatus
}
// KernelStatus is the aggregated runtime snapshot of all kernel subsystems.
type KernelStatus struct {
Uptime string `json:"uptime"`
StartTime string `json:"start_time"`
// Build 是内核自身的版本与构建信息。
//
// 为何需要:此前 WebUI 展示的“版本”取自 `sdk.SDKVersion`,那是 **SDK 仓
// meta.Version 的硬编码值**;而 `-ldflags` 注入的是内核的
// `internal/meta.Version`——两条链完全不相交。于是:
// - 构建时注入的真实版本号、commit、构建时间全部丢失
// - 两仲版本号碰巧相等时看不出问题,一旦不等就报错版本;
// - 无法回答“现网跑的是哪个 commit 构出来的”。
Build BuildStatus `json:"build"`
AgentID string `json:"agent_id"`
Plugins []PluginInfo `json:"plugins"`
Tools []ToolDef `json:"tools"`
Channels []ChannelInfo `json:"channels"`
// InputChannels 是 inputch 的**登记与归属**视图(谁注册、划给了哪个 agent、
// 容量、默认回程输出)。
//
// 为何单列Channels 只描述设备侧能力,回答不了「这条输入归谁」。驻留子 agent
// 出现之后,归属才是运行态里最该看见的东西——只画设备能力,等于把
// 「输入路由发生在进内核之前」这条设计事实藏了起来。
InputChannels []InputChannelInfo `json:"input_channels"`
Memory MemoryStatus `json:"memory"`
Knowledge KnowledgeStatus `json:"knowledge"`
Documents DocumentStatus `json:"documents"`
TextMemory TextMemoryStatus `json:"text_memory"`
Social SocialStatus `json:"social"`
LLM LLMStatus `json:"llm"`
Context ContextStatus `json:"context"`
Runtime RuntimeStatus `json:"runtime"`
// ONNX 报告统一多模态向量空间ONNX 模型)是否**真的在用**。
//
// 为何单列:内核的向量能力是三层降级(统一多模态空间 → 词嵌入 → TF-IDF
// 只报「向量可用/不可用」分不清「ONNX 模型已加载」与「退回了纯文本路径」。
// 模型缺失 / 运行时缺失 / provider 打开失败时这里是 enabled=false + reason。
ONNX ONNXStatus `json:"onnx"`
Tracker TrackerStatus `json:"tracker"`
// Residents 是驻留式子 agent 的运行时视图(数量 = len(Residents))。
Residents []ResidentStatus `json:"residents"`
// Scheduler 是输入调度器的运行时快照(可观测性,设计文档 §11 O1/O2
// M2 起输入不再直接排队在 channel 上,而是经 readyQueue/pendingInterrupts/
// suspendStack 三集合按优先级调度;这里把这些状态暴露出来。
Scheduler SchedulerStatus `json:"scheduler"`
}
// SchedulerStatus 是调度器的原子快照 DTO。
type SchedulerStatus struct {
// Running 是当前执行的任务(空表示空闲)。
Running *SchedulerTask `json:"running,omitempty"`
// Immediate 是刚抢占成功、将在下一个安全点立即运行的中断(最多一个)。
Immediate *SchedulerTask `json:"immediate,omitempty"`
// ReadyQueueDepth / PendingInterrupts / SuspendStack 是三个集合的深度。
ReadyQueueDepth int `json:"ready_queue_depth"`
PendingInterrupts int `json:"pending_interrupts"`
SuspendStack int `json:"suspend_stack"`
MaxSuspendDepth int `json:"max_suspend_depth"`
// InterruptQueues 是**四条中断队列各自的深度**下标即中断级别1..4
// 下标 0 恒为 0这样 level 可以直接当数组下标用,省掉调用方 ±1 的翻译。
//
// 为什么单列PendingInterrupts 只是总数,看不清"堵在哪一级"——
// 四级中断是抢占优先级,堵在 L1 还是 L4 是完全不同的运行状态。
InterruptQueues [5]int `json:"interrupt_queues"`
// SuspendFrames 是中断栈的帧,**栈底 → 栈顶**(只暴露任务标识,不含帧内容)。
// 深度见 SuspendStack帧的顺序回答了"谁被谁打断"。
SuspendFrames []SchedulerFrame `json:"suspend_frames,omitempty"`
// InterruptsByLevel / PreemptsByLevel 是各级中断的累计计数(下标 1..4
// 前者=被登记次数(含没抢成的),后者=判定可抢占并进入 immediate 的次数。
InterruptsByLevel [5]uint64 `json:"interrupts_by_level"`
PreemptsByLevel [5]uint64 `json:"preempts_by_level"`
Enqueued uint64 `json:"enqueued"`
Executed uint64 `json:"executed"`
Rejected uint64 `json:"rejected"`
Suspended uint64 `json:"suspended"`
Resumed uint64 `json:"resumed"`
// Preempted = Σ PreemptsByLevel[1..4],即「真正抢占成功」的次数。
// 它与 Suspended 不等价(受害者可能先自行结束),因此不是 Suspended 的别名。
Preempted uint64 `json:"preempted"`
// Backpressure 是就绪队列满、输入被挡回 channel 的次数(暂时不收,不是丢弃)。
Backpressure uint64 `json:"backpressure"`
}
// SchedulerFrame 是中断栈里的一帧(供图形化展示"压了几层现场")。
type SchedulerFrame struct {
Task SchedulerTask `json:"task"`
}
// ResidentStatus 是驻留式子 agent 的运行时视图。
//
// 为什么进状态面:驻留子是"常驻的独立 agent",它们的数量、轮次与上下文占用
// 是运行态里最需要一眼看到的东西此前只在日志里WebUI 只能显示文字)。
type ResidentStatus struct {
ID string `json:"id"`
State string `json:"state"`
Rounds int `json:"rounds"`
ContextFull bool `json:"context_full"`
InputChs []string `json:"input_channels,omitempty"`
AllowedOutputs []string `json:"allowed_outputs,omitempty"`
InputChTable int `json:"input_ch_table"`
CreatedAt string `json:"created_at,omitempty"`
// 以下四项是该驻留子**自己的**调度器积压摘要,用于 per-agent 负载环形图。
//
// 根 agent 的积压看 KernelStatus.Scheduler每个驻留子是独立 agent、
// 各跑各的调度器,必须分别给,否则「哪个子忙」在界面无从判断。
ReadyQueueDepth int `json:"ready_queue_depth"`
PendingInterrupts int `json:"pending_interrupts"`
SuspendStack int `json:"suspend_stack"`
InterruptQueues [5]int `json:"interrupt_queues"`
}
// SchedulerTask 是任务的最小标识(不暴露帧内容)。
type SchedulerTask struct {
ID uint64 `json:"id"`
Level int `json:"level"`
Kind string `json:"kind"`
}
// ONNXStatus 是统一多模态向量空间ONNX 模型)的启用状态与身份。
type ONNXStatus struct {
// Enabled 是 provider 真正打开且元数据合法(不是「配置里写了 provider」
Enabled bool `json:"enabled"`
// Provider 是配置指定的 provider 名(如 chineseclip / qwen3vl / http
Provider string `json:"provider,omitempty"`
Dim int `json:"dim,omitempty"`
Fingerprint string `json:"fingerprint,omitempty"`
Modalities []string `json:"modalities,omitempty"`
// Reason 是未启用时的原因(未配置 / 打开失败的具体错误 / 其它)。
Reason string `json:"reason,omitempty"`
}
type PluginInfo struct {
Name string `json:"name"`
Loaded bool `json:"loaded"`
}
type ChannelInfo struct {
Name string `json:"name"`
// Type 保持为 DeviceType 的数字字符串(历史字段,别改语义)。
Type string `json:"type"`
// Direction 是方向的可读名in只进/ out只出/ io双向
Direction string `json:"direction"`
Ready bool `json:"ready"`
// 以下三项供通道拓扑展示:此前 collectKernelStatus 只透传了 Name/Type
// 把 Description/Tools/OutputCaps 全丢了,前端只能画出一排光秃秃的名字。
Description string `json:"description,omitempty"`
Tools []string `json:"tools,omitempty"`
OutputCaps int `json:"output_caps"`
CapsText string `json:"caps_text,omitempty"`
}
// InputChannelInfo 是一条 inputch 的登记与归属视图。
//
// 字段取自 agent/io 的 ChannelRegistry根 agent 与驻留子**共用同一份**登记表),
// 因此它天然覆盖驻留子的通道分配。
type InputChannelInfo struct {
Name string `json:"name"`
// Plugin 是注册它的插件名(归属可追溯)。
Plugin string `json:"plugin,omitempty"`
// Owner 是被划给的 agent id"" = 未分配,归根 agent / 内核默认。
Owner string `json:"owner,omitempty"`
// Capacity 是该 inputch 的队列容量0 = 用内核默认值。
Capacity int `json:"capacity,omitempty"`
// Output 是该 inputch 的默认回程输出通道;"" = 由来源决定。
Output string `json:"output,omitempty"`
}
type MemoryStatus struct {
Available bool `json:"available"`
EntityCount int `json:"entity_count"`
RelationCount int `json:"relation_count"`
EntityTypes int `json:"entity_types"`
}
type KnowledgeStatus struct {
Available bool `json:"available"`
ItemCount int `json:"item_count"`
Items []string `json:"items,omitempty"`
}
type DocumentStatus struct {
Available bool `json:"available"`
DocCount int `json:"doc_count"`
VectorCount int `json:"vector_count"`
}
type TextMemoryStatus struct {
Available bool `json:"available"`
FileCount int `json:"file_count"`
}
type SocialStatus struct {
Available bool `json:"available"`
PersonCount int `json:"person_count"`
}
type LLMStatus struct {
Available bool `json:"available"`
Provider string `json:"provider,omitempty"`
Sources int `json:"sources,omitempty"`
}
type ContextStatus struct {
EventCount int `json:"event_count,omitempty"`
}
type RuntimeStatus struct {
Goroutines int `json:"goroutines"`
MemoryMB int64 `json:"memory_mb"`
GoVersion string `json:"go_version"`
}
// BuildStatus 是内核二进制的构建身份,全部来自 `internal/meta`
// (由 -ldflags 在构建时注入,未注入时为源码默认值/unknown
type BuildStatus struct {
// Version 是内核语义版本(如 1.0.0)。
Version string `json:"version"`
// Commit 是构建时的 Git 短 hash未注入为 unknown。
Commit string `json:"commit"`
// BuildTime 是 UTC 构建时间;未注入为 unknown。
BuildTime string `json:"build_time"`
// SDKCompatible 是本内核可兼容的最高 SDK 版本。
// 插件用旧 SDK 编译时靠它判断能不能加载。
SDKCompatible string `json:"sdk_compatible"`
// KernelName 是内核名HomeAgent
KernelName string `json:"kernel_name"`
// SourceURL 是本次构建对应的源码地址。AGPL-3.0 §13 要求:向使用者提供网络
// 服务时,要给他们拿到 Corresponding Source 的机会——WebUI 状态页会把它渲染成
// 可见链接,所以**修改后对外部署的分支必须把这个值改指向自己的源码仓库**。
SourceURL string `json:"source_url,omitempty"`
}
type TrackerStatus struct {
Available bool `json:"available"`
Dir string `json:"dir,omitempty"`
}