feat(gateway): admin 列表端点接真实数据——persona/session/memory 补 List() 并注入 gateway.Deps
根因:gateway.Server 定义 SessionStore/PersonaStore/MemoryStore 接口但生产从未满足:
- 底层 manager 无 List() 方法;
- wireFrontend 的 gateway.Deps{} 未传 Session/Personas/Memories。
→ /api/v1/sessions|personas 与 /api/v1/admin/{sessions,personas,memories} 恒返回 []。
改动:
- persona/registry:Registry.List() []Character(并发安全、值拷贝)。
- channel/session:SessionManager.List(ctx)(查 channel_sessions 表+按 actor_role 重建)。
- runtime/memory:Store.List(ctx)(全表,复用 scanItems)。
- gateway 三 Store 接口改为返回域类型(Character/MemoryItem),映射统一放 collect* 侧。
- cmd/cyrene/wire.go:Deps 补传 Session/Personas/Memories。
- .gitignore:cyrene→/cyrene(锚定根,不再误伤 cmd/cyrene 目录)。
实机验证:/api/v1/admin/personas 返回 {id:cyrene,name:昔涟,isDefault:true}。
This commit is contained in:
1 parent
5dae2b9741
commit
04bfa2c7a7
11 files changed
+312
-18
No files matched your search
@@ -156,7 +156,9 @@ func (s *Server) collectMemories(ctx context.Context) []MemorySummary {
|
||||
s.log.Error("list memories", "err", err)
|
||||
return out
|
||||
}
|
||||
out = append(out, list...)
|
||||
for _, it := range list {
|
||||
out = append(out, MemorySummary{ID: it.ID, Scope: string(it.Scope), Text: it.Content})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
|
||||
@@ -158,12 +158,33 @@ func (s *Server) handleListPersonas(w http.ResponseWriter, r *http.Request) {
|
||||
// collectPersonas returns a non-nil persona slice from the configured store.
|
||||
func (s *Server) collectPersonas() []PersonaSummary {
|
||||
out := make([]PersonaSummary, 0)
|
||||
if s.personas != nil {
|
||||
out = append(out, s.personas.List()...)
|
||||
if s.personas == nil {
|
||||
return out
|
||||
}
|
||||
for _, c := range s.personas.List() {
|
||||
id := c.PersonaID
|
||||
if id == "" {
|
||||
id = c.ID
|
||||
}
|
||||
out = append(out, PersonaSummary{
|
||||
ID: id,
|
||||
Name: c.Name,
|
||||
Character: c.Name,
|
||||
IsDefault: c.Default,
|
||||
Mode: firstMode(c.Modes),
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// firstMode returns the first declared behavior mode, or "" when none are set.
|
||||
func firstMode(modes []string) string {
|
||||
if len(modes) == 0 {
|
||||
return ""
|
||||
}
|
||||
return modes[0]
|
||||
}
|
||||
|
||||
// summaryOfSession maps a session.Session to its wire shape.
|
||||
func summaryOfSession(sess session.Session) SessionSummary {
|
||||
return SessionSummary{
|
||||
|
||||
@@ -34,7 +34,9 @@ import (
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/config"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/iot"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/logger"
|
||||
personareg "git.yeij.top/AskaEth/Cyrene_v2/internal/persona/registry"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/loop"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/memory"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
|
||||
)
|
||||
|
||||
@@ -69,23 +71,24 @@ type Chatter interface {
|
||||
Run(ctx context.Context, sessionID string, messages []model.Message) (*loop.Result, error)
|
||||
}
|
||||
|
||||
// SessionStore lists known channel sessions. The concrete session manager does
|
||||
// not yet expose a list method, so production wiring may leave Sessions nil and
|
||||
// the handlers return [].
|
||||
// SessionStore lists known channel sessions. *session.SessionManager is the
|
||||
// production implementation.
|
||||
type SessionStore interface {
|
||||
List(ctx context.Context) ([]session.Session, error)
|
||||
}
|
||||
|
||||
// PersonaStore lists persona summaries. The concrete persona registry does not
|
||||
// yet expose a list method, so production wiring may leave Personas nil.
|
||||
// PersonaStore lists registered characters (each bound one-to-one to a persona).
|
||||
// *persona/registry.Registry is the production implementation. The gateway maps
|
||||
// each Character to its wire summary; the interface deliberately returns the
|
||||
// domain type so the wire shape stays out of the store contract.
|
||||
type PersonaStore interface {
|
||||
List() []PersonaSummary
|
||||
List() []personareg.Character
|
||||
}
|
||||
|
||||
// MemoryStore lists memory entries. The concrete memory store does not yet
|
||||
// expose a list method, so production wiring may leave Memories nil.
|
||||
// MemoryStore lists memory entries. *runtime/memory.Store is the production
|
||||
// implementation. The gateway maps each MemoryItem to its wire summary.
|
||||
type MemoryStore interface {
|
||||
List(ctx context.Context) ([]MemorySummary, error)
|
||||
List(ctx context.Context) ([]memory.MemoryItem, error)
|
||||
}
|
||||
|
||||
// IoTStore lists IoT devices. *iot.Manager is the production implementation.
|
||||
@@ -96,8 +99,9 @@ type IoTStore interface {
|
||||
// Deps carries the gateway's injected dependencies. Every field is nil-tolerant
|
||||
// except Auth, which is required (authentication backs login and every RBAC
|
||||
// decision). Registry/Loop are satisfied by the concrete *capability.Registry and
|
||||
// *loop.Loop; Sessions/Personas/Memories remain nil until their managers expose a
|
||||
// list method, in which case the handlers return [].
|
||||
// *loop.Loop; Sessions/Personas/Memories are satisfied by the concrete session
|
||||
// manager, persona registry and memory store, and the handlers return [] only
|
||||
// when a dependency is left nil.
|
||||
type Deps struct {
|
||||
// Log is the base logger. Nil uses a discard logger.
|
||||
Log *slog.Logger
|
||||
|
||||
Reference in new issue
Block a user