- 断点已证 = **时序层**:graph_update 只走实时帧从不重放、flowGraphs 不持久化、补拉通路此前根本不存在(EndRound 注释承诺过「刷新能重放」,代码里从来没有)
铁证:15:16:38 页面重载抹掉 15:09 那轮图,而下一轮心跳要等 ~15:24 ⇒ 打开后台思考页时桶必然为空
- 新增只读端点 GET /api/v1/admin/flow/graph?sessionId=(owner|admin;省略=主会话;graph 与 graph_update 帧的 data 逐字同形)
无图 ⇒ 200 + graph:null(不画假图);图源未接线 ⇒ 500 flow_unavailable(不伪装成「没有图」);不审计、不发布
- loop.FlowPublisher.LastGraph:只读快照(不发布/不改图/不动轮次计数),FlowGraph.Clone 深拷贝避免锁外编码撕裂
- 前端 useFlowSnapshot:只在「本会话还没有图」时补拉(避免每行一个请求);Flow/Agents/Backthink 三处接入 + 来源说明条(明确「最近一轮」与「多轮历史回放尚未实现」)
- 变异实测:LastGraph 恒 nil ⇒ 4 条测试红;白名单去掉 sess-backthink ⇒ 对应测试红(首次变异因未使用 import 编译失败 ⇒ 已作废重做)
- ⚠️ 诚实边界:每会话只回**最近一轮**(多轮回放属 F2);白名单外会话(IM 群聊/陌生人)永远没有图;**后端重启后未跑新轮次前端点如实返 null(图是内存资产,不落库)**—— 主人要的「本地数据」正是 F2 要补的
164 lines
8.5 KiB
Go
164 lines
8.5 KiB
Go
package gateway
|
||
|
||
import (
|
||
"database/sql"
|
||
"io/fs"
|
||
"log/slog"
|
||
"net/http"
|
||
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/bus"
|
||
pluginmgr "git.yeij.top/AskaEth/Cyrene_v2/internal/capability/plugin"
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
|
||
)
|
||
|
||
// VectorState 是组合根报告的向量增强(pgvector)运行状态,供管理侧
|
||
// 「存储状态」端点回答「PG 到底有没有生效」(design/03 §3)。
|
||
//
|
||
// 它是**复用**而非探测:网关不读环境变量、不新开 PG 连接、不
|
||
// 自行 ping —— 真相只有组合根知道(DB_PG_URL 是否配置 + 活的向量
|
||
// 索引是哪个后端),因此由它注入,避免面板看到与运行时不一致的
|
||
// 第二个判断。
|
||
type VectorState struct {
|
||
// Configured 报告 DB_PG_URL 是否已配置(非空即算),即
|
||
// 增强开关在不在。
|
||
Configured bool
|
||
// Live 报告当前活的向量索引确实是 PostgreSQL+pgvector 后端。
|
||
// 配置了但连接/schema 准备失败时为 false —— 此时语义检索已降级,
|
||
// 面板必须显示「未就绪」而不是假装增强生效。
|
||
Live bool
|
||
}
|
||
|
||
// Deps 承载网关被注入的依赖。除 Auth 外每个字段都容忍
|
||
// nil,Auth 是必需的(认证支撑登录与每一个 RBAC
|
||
// 决策)。Registry/Loop 由具体的 *capability.Registry 与
|
||
// *loop.Loop 满足;Sessions/Personas/Memories 由具体的会话
|
||
// 管理器、人格注册表与记忆存储满足,只有当依赖留为
|
||
// nil 时 handler 才返回 []。
|
||
type Deps struct {
|
||
// Log 是基础 logger。为 nil 时使用丢弃型 logger。
|
||
Log *slog.Logger
|
||
// Auth 是 JWT/RBAC 服务。必需。
|
||
Auth Authenticator
|
||
// Bus 是 WS hub 所订阅的进程内事件总线。可选。
|
||
Bus bus.Bus
|
||
// Registry 枚举能力/插件/渠道。可选。
|
||
Registry CapabilityStore
|
||
// Loop 运行聊天回合。可选(未设置时 chat 返回错误)。
|
||
Loop Chatter
|
||
// Session 列出渠道会话。可选。
|
||
Session SessionStore
|
||
// Personas 列出人格。可选。
|
||
Personas PersonaStore
|
||
// Memories 列出记忆条目。可选。
|
||
Memories MemoryStore
|
||
// History 是持久化聊天历史存储(design/16)。可选;为 nil 时
|
||
// 会话/消息端点退化(列出回退到渠道会话,其余 501)。
|
||
History HistoryStore
|
||
// IoT 列出 IoT 设备。可选。
|
||
IoT IoTStore
|
||
// Scheduler 为 subagent_ask WS 路由审计子代理上下文。
|
||
// 可选(未设置时 subagent_ask 返回明确的错误)。
|
||
Scheduler SubagentAuditor
|
||
// Tasks 为 task_output_query WS 路由查询任务输出。
|
||
// 可选(未设置时 task_output_query 返回明确的错误)。
|
||
Tasks TaskOutputStore
|
||
// Automations 列出自动化与提醒。可选。
|
||
Automations AutomationStore
|
||
// Users 列出账号与 API key。可选(回退到已配置的
|
||
// 单个管理账号)。
|
||
Users UserStore
|
||
// Refresh 是非透明 refresh token 存储。可选:为 nil 时登录省略
|
||
// refreshToken,/auth/refresh + /auth/logout 返回 not-configured。
|
||
Refresh RefreshGrantStore
|
||
// Backthink 列出后台思考记录。可选。
|
||
Backthink BackthinkStore
|
||
// RAG 支撑管理侧知识库 RAG 模块。可选;未设置时列出/搜索
|
||
// 返回空,写端点报告明确的 501。
|
||
RAG RagStore
|
||
// LLM 是可热切换的 provider 栈(models.json,design/04 §3.1)。
|
||
// 可选:为 nil 时管理 /llm 端点回退到环境配置,使
|
||
// 既有的网关测试继续可用。
|
||
LLM *model.RuntimeLLM
|
||
// EnvPath 是进程启动时解析的 `.env` 文件路径(组合根传给 config.Load 的同一个)。
|
||
// 「重置为 env 默认」动作(切片 R1)按**既有 config 解析入口**重读 env 默认层,
|
||
// 网关自己绝不 fopen `.env`。空表示只看进程环境变量(与 config.Load("") 的
|
||
// 约定一致,生产走 systemd/env_file 时就是这种形态)。可选。
|
||
EnvPath string
|
||
// Channels 是运行时可编辑的渠道适配器配置(channels.json)。
|
||
// 可选:为 nil 时管理 /channels/config 端点返回明确的
|
||
// not-configured 错误,与 LLM 栈未设置时的行为一致。
|
||
Channels ChannelConfigStore
|
||
// Plugins 是运行时可安装的外部工具 provider 管理器
|
||
// (plugins.json + 活的 MCP server)。可选:为 nil 时安装返回
|
||
// 明确的 not-implemented 错误,卸载回退为普通的能力
|
||
// 移除,使既有的网关测试继续可用。
|
||
Plugins *pluginmgr.Manager
|
||
// OwnerRegistrar 把扫码登录绑定的主人 id 盖进主人
|
||
// 白名单(configs/users/owner.yaml)并热更新活的 profile。
|
||
// 可选:为 nil 时 weixin 确认流程仍会持久化 channels.json,但
|
||
// 跳过白名单登记(按设计即为尽力而为)。
|
||
OwnerRegistrar OwnerRegistrar
|
||
// AuditStore 持久化管理审计链(observability → audit)。为 nil 时
|
||
// 网关退化为内存存储,使端点仍能返回
|
||
// 数据;组合根注入基于 a.db 的 NewSQLiteAuditStore 以获得真实
|
||
// 持久化。可选。
|
||
AuditStore AuditStore
|
||
// DatabasePath 是组合根实际打开的 SQLite 数据库文件解析后
|
||
// 路径(由 resolveSQLitePath 推导的值,当数据目录默认值
|
||
// 生效时可能与 cfg.DB.SQLitePath 不同)。它支撑
|
||
// 管理备份/恢复端点。可选;为空时那些端点诚实作答,
|
||
// 返回明确的 not-configured 错误。
|
||
DatabasePath string
|
||
// DataDir 是解析后的数据目录(resolveDataDir 返回的值,当操作系统
|
||
// 默认值生效时可能与 cfg.DataDir 不同)。它支撑
|
||
// 图片上传存储(<DataDir>/uploads)及其静态路由。可选;
|
||
// 为空时上传 handler 回退到 cfg.DataDir。
|
||
DataDir string
|
||
// Database 是组合根已打开的活 SQLite 连接池。管理侧的
|
||
// 「存储状态」只读端点用它读页级统计与 documents 表 ——
|
||
// 复用既有池,端点自身不另开连接或连接池。可选;为 nil 时
|
||
// 该端点诚实作答(500 storage_unavailable),绝不假装
|
||
// 拿到了数据。
|
||
Database *sql.DB
|
||
// Vector 是组合根报告的向量增强(pgvector)运行时状态,
|
||
// 见 VectorState。网关只读它,绝不自行探测。可选;零值
|
||
// 表示「未配置」(kind:"none"),与未启用增强的部署一致。
|
||
Vector VectorState
|
||
// Streaming 标记注入的 Loop 具备流式能力(其 OnStream
|
||
// 已接线为发布 ws.stream_chunk)。设置后 hub 会跳过它自己的
|
||
// 单次最终 stream_chunk 发送,因为增量已通过 OnStream 流出。
|
||
Streaming bool
|
||
// Frontend 是为所有非 API、非 WS 路由提供的 SPA 文件系统。
|
||
// 为 nil 时网关不提供任何静态资产(只有 API 与 WS)。
|
||
// 使用内嵌的 dist(internal/webui)或外部 dist 目录。
|
||
Frontend fs.FS
|
||
// Webhooks 是外部挂载的入站 HTTP handler(端点路径 →
|
||
// handler),通常来自接收 webhook 回调的渠道适配器
|
||
// (例如 webhook)。每个都挂到 ServeMux 上且不经网关认证;
|
||
// handler 自身强制其签名/授权(webhook HMAC)。
|
||
// 可选。
|
||
Webhooks map[string]http.Handler
|
||
// Usage 是 LLM 用量汇总的只读出口(切片 U1)。可选;为 nil 时
|
||
// GET /api/v1/admin/llm/usage 诚实作答 500 usage_unavailable,
|
||
// 绝不回一份全 0 的假汇总。
|
||
Usage LlmUsageStore
|
||
// EventStore 是渠道事件留存的只读查询出口(design/26 §4.5;切片 E6)。
|
||
// 组合根注入的正是交给桥接层写入的**同一个** `*events.SQLStore` 句柄
|
||
// (同一个库、同一份口径)。可选;为 nil 时
|
||
// GET /api/v1/admin/channels/events 与 `.../counters` 诚实作答
|
||
// 500 channel_events_unavailable,绝不回一份全 0 的假汇总。
|
||
EventStore ChannelEventStore
|
||
// MaxParallelTurns 是单会话在途并行路数的上限(design/15 §2.5.7)。
|
||
// 零值/负数 ⇒ 编排器用默认 2;1 ⇒ 关闭真并行(恒 1 路,完全回落到
|
||
// queue + 回合内 steer 的现状);超过硬上限 3 ⇒ 钳到 3。
|
||
// 它刻意是编排器的构造期旋钮而不是一个全局:真并行只由显式声明
|
||
// (上行 `chat.parallel`)触发,因此调大它不会改变任何未声明并行的客户端行为。
|
||
MaxParallelTurns int
|
||
// Flow 是「最近一轮链路图」的只读出口(契约 v0.71 的
|
||
// GET /api/v1/admin/flow/graph)。组合根注入的正是交给 loop 的那个
|
||
// *loop.FlowPublisher —— 同一个对象,因此查询面读到的就是实时发布的那张图。
|
||
// 可选;为 nil 时端点诚实作答 500 flow_unavailable,绝不回
|
||
// graph:null(那会把「图源没接线」伪装成「这一轮确实没有图」)。
|
||
Flow FlowGraphSource
|
||
}
|