执行方案 DevDocs/audit/_plan.md 阶段 0 · G0-C:该文件是全仓第二大超限文件(666 行), 且后续多条裁决要改它(工具策略落盘、主人档案 GET/PUT、admin API 补推送结果、模型配置 自动化)⇒ 先拆。 - admin.go(169):共享地基 —— backthinkListLimit 常量、全部 DTO 类型、 collectSessions/collectMemories 收集器、iotDeviceSummary - admin_query.go(467):只读 GET 聚合(personas/sessions/memories/plugins/channels/iot/ llm/automations/users/backthink/rag 的列表与查询 handler + 渠道账号脱敏等私有辅助) - admin_mutate.go(41):写操作(adminSetPolicy,带审计的 owner 写) 纯搬移机械证明:拆前与拆后(非空、非 package、非 import 块行)排序后 **md5 相同** (605=605 行);顶层声明集合 43 条守恒;唯一新增 = 两个新文件的 package 行与 import 块。 未触碰 admin_write_*.go / admin_channels_*.go 及任何 _test.go。 验证:go build/vet 绿;internal/services/gateway 测试绿(含 -run Admin 定向); linux/amd64 + darwin/arm64 交叉编译绿;三文件 169/467/41 行均 ≤500;gofmt -l 无输出。
170 lines
5.6 KiB
Go
170 lines
5.6 KiB
Go
package gateway
|
||
|
||
import "context"
|
||
|
||
// backthinkListLimit 是未指定 limit 时管理面板索取的
|
||
// 最近 think 记录条数。
|
||
const backthinkListLimit = 50
|
||
|
||
// PluginSummary 是管理列表中一个能力/插件的线上结构。
|
||
type PluginSummary struct {
|
||
Name string `json:"name"`
|
||
Kind string `json:"kind"`
|
||
Description string `json:"description"`
|
||
AllowInGroup bool `json:"allowInGroup"`
|
||
AllowInStranger bool `json:"allowInStranger"`
|
||
}
|
||
|
||
// ChannelSummary 是一个已注册渠道适配器的线上结构。Accounts
|
||
// 承载该平台已配置的账号(已脱敏,不含原始 token),使
|
||
// 面板能展示并编辑账号配置;当 s.channels 未接线
|
||
// 或该平台没有已配置账号时省略。
|
||
//
|
||
// NeedsRescan/LastError(v0.39)报告适配器需要主人重新授权
|
||
// (见 admin_channels_rescan.go 中的 rescanAware);二者仅在适配器
|
||
// 确实要求时才出现,否则一律省略。
|
||
type ChannelSummary struct {
|
||
Name string `json:"name"`
|
||
Connected bool `json:"connected"`
|
||
NeedsRescan bool `json:"needsRescan,omitempty"`
|
||
LastError string `json:"lastError,omitempty"`
|
||
Accounts []AdminChannelAccount `json:"accounts,omitempty"`
|
||
}
|
||
|
||
// policyRequest 是 POST /api/v1/admin/plugins/policy 的请求体。
|
||
type policyRequest struct {
|
||
Name string `json:"name"`
|
||
AllowInGroup bool `json:"allowInGroup"`
|
||
AllowInStranger bool `json:"allowInStranger"`
|
||
}
|
||
|
||
// AdminLlmProvider 是管理配置中一个 LLM provider 的线上结构。
|
||
// API key 刻意缺位:它绝不返回给客户端。
|
||
type AdminLlmProvider struct {
|
||
ID string `json:"id"`
|
||
Name string `json:"name"`
|
||
Provider string `json:"provider"`
|
||
BaseURL string `json:"baseUrl"`
|
||
Model string `json:"model"`
|
||
Multimodal bool `json:"multimodal"`
|
||
Enabled bool `json:"enabled"`
|
||
Fallback string `json:"fallback,omitempty"`
|
||
// MaxTokens 是该分组自身的 token 预算(0 = 未设置;此时运行时
|
||
// 在最后一个 fallback 步骤回退到 LLM_FALLBACK_MAX_TOKENS,
|
||
// 再回退到适配器默认值)。
|
||
MaxTokens int `json:"maxTokens,omitempty"`
|
||
}
|
||
|
||
// AdminLlmConfig 是 GET /api/v1/admin/llm 的线上结构。
|
||
type AdminLlmConfig struct {
|
||
Providers []AdminLlmProvider `json:"providers"`
|
||
}
|
||
|
||
// AdminAutomationRecord 是管理列表中一条自动化/提醒的线上结构。
|
||
// 对 cron 类型,Cron 承载 cron 表达式;lastRun 与
|
||
// nextRun 在值未知时省略。
|
||
type AdminAutomationRecord struct {
|
||
ID string `json:"id"`
|
||
Name string `json:"name"`
|
||
Kind string `json:"kind"`
|
||
Cron string `json:"cron,omitempty"`
|
||
Enabled bool `json:"enabled"`
|
||
LastRun string `json:"lastRun,omitempty"`
|
||
NextRun string `json:"nextRun,omitempty"`
|
||
}
|
||
|
||
// AdminUserRecord 是管理列表中一个账号/API key 的线上结构。
|
||
type AdminUserRecord struct {
|
||
ID string `json:"id"`
|
||
Username string `json:"username"`
|
||
Role string `json:"role"`
|
||
CreatedAt string `json:"createdAt,omitempty"`
|
||
}
|
||
|
||
// AdminBackthinkItem 是管理监控列表中一条后台思考记录的
|
||
// 线上结构。
|
||
type AdminBackthinkItem struct {
|
||
ID string `json:"id"`
|
||
Trigger string `json:"trigger"`
|
||
Conclusion string `json:"conclusion,omitempty"`
|
||
ShouldNotify bool `json:"shouldNotify"`
|
||
Pushed bool `json:"pushed"`
|
||
At int64 `json:"at"`
|
||
}
|
||
|
||
// AdminRagDoc 是管理 RAG 列表中一个知识库文档(项目索引
|
||
// 条目)的线上结构。
|
||
type AdminRagDoc struct {
|
||
ID string `json:"id"`
|
||
Name string `json:"name"`
|
||
Desc string `json:"desc,omitempty"`
|
||
Chunks int `json:"chunks"`
|
||
Embedded bool `json:"embedded"`
|
||
}
|
||
|
||
// AdminRagHit 是一条 RAG 检索命中的线上结构。
|
||
type AdminRagHit struct {
|
||
DocID string `json:"docId"`
|
||
DocName string `json:"docName"`
|
||
Chapter string `json:"chapter,omitempty"`
|
||
Text string `json:"text"`
|
||
Score float64 `json:"score"`
|
||
Semantic bool `json:"semantic"`
|
||
}
|
||
|
||
// AdminRagResponse 是 GET /api/v1/admin/rag 的线上结构。Hits 仅
|
||
// 在提供了查询参数时出现,因此调用方能区分「未请求搜索」
|
||
// 与「搜索了但没找到」。
|
||
type AdminRagResponse struct {
|
||
Documents []AdminRagDoc `json:"documents"`
|
||
Hits []AdminRagHit `json:"hits,omitempty"`
|
||
}
|
||
|
||
// ragQueryRequest 是 POST /api/v1/admin/rag/query 的请求体。
|
||
type ragQueryRequest struct {
|
||
Query string `json:"query"`
|
||
}
|
||
|
||
// collectSessions 从已配置的存储返回非 nil 的会话切片。
|
||
func (s *Server) collectSessions(ctx context.Context) []SessionSummary {
|
||
out := make([]SessionSummary, 0)
|
||
if s.sessions == nil {
|
||
return out
|
||
}
|
||
list, err := s.sessions.List(ctx)
|
||
if err != nil {
|
||
s.log.Error("list sessions", "err", err)
|
||
return out
|
||
}
|
||
for _, sess := range list {
|
||
out = append(out, summaryOfSession(sess))
|
||
}
|
||
return out
|
||
}
|
||
|
||
// collectMemories 从已配置的存储返回非 nil 的记忆切片。
|
||
func (s *Server) collectMemories(ctx context.Context) []MemorySummary {
|
||
out := make([]MemorySummary, 0)
|
||
if s.memories == nil {
|
||
return out
|
||
}
|
||
list, err := s.memories.List(ctx)
|
||
if err != nil {
|
||
s.log.Error("list memories", "err", err)
|
||
return out
|
||
}
|
||
for _, it := range list {
|
||
out = append(out, MemorySummary{ID: it.ID, Scope: string(it.Scope), Text: it.Content})
|
||
}
|
||
return out
|
||
}
|
||
|
||
// iotDeviceSummary 是一个 IoT 设备的线上结构。
|
||
type iotDeviceSummary struct {
|
||
ID string `json:"id"`
|
||
Name string `json:"name"`
|
||
Type string `json:"type"`
|
||
State map[string]any `json:"state"`
|
||
Online bool `json:"online"`
|
||
}
|