feat: 角色视觉体系(头像按角色取)+ 时间注入(loop 每轮当前时间)
【角色视觉体系(红线:每个角色自己的头像/背景,绝不串用昔涟)】
- persona.go:Persona 加 Visual{avatar, chatBackground{landscape,portrait}} + DefaultAvatar;每个角色各自配。
- cyrene.yaml:昔涟配 avatar(3F-Q-Happy-1) + chatBackground(横/竖屏)。
- PersonaStore 加 Persona(id);PersonaSummary 加 avatar/chatBackground;collectPersonas 按角色取
Persona(id) 视觉(无视觉→空,前端回退默认占位,绝不串角色)。
- 前端:types PersonaRecord 加 avatar/chatBackground;persona.ts personaAvatar(p)=p?.avatar||默认占位
(殊无昔涟 fallback);store 加 currentPersona;App 挂载 fetchPersonas 取默认角色;
TopBar/chat 头像改 personaAvatar(currentPersona)(写死昔涟头像已清除)。
【时间注入(她自然知道现在几点,深夜催睡交给人格/capacity)】
- options.go Options 加 Timezone;loop.go Loop 加 timeLocation/timeZoneName + New 解析 + loadTimezone;
time.go currentTimeBlock()(当前时间+周几+时区,每轮刷新);memory.go assembleContext 在「工作记忆」
前注入时间 system(keyed 在 timeLocation!=nil,无时区不注入不破坏测试);wire.go Timezone=a.cfg.Timezone。
go build/vet/test 全绿(gateway/loop/persona);前端 tsc/vite build 75模块绿。红线无写死昔涟头像。
This commit is contained in:
1 parent
950bea9758
commit
7455d09d05
20 files changed
+177
-6
No files matched your search
@@ -21,6 +21,7 @@ import (
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/channel/session"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/config"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/iot"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/persona/loader"
|
||||
personareg "git.yeij.top/AskaEth/Cyrene_v2/internal/persona/registry"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/knowledge"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/loop"
|
||||
@@ -180,6 +181,10 @@ type stubPersonas struct {
|
||||
|
||||
func (s *stubPersonas) List() []personareg.Character { return s.list }
|
||||
|
||||
// Persona satisfies PersonaStore; tests don't rely on visual assets, so it
|
||||
// always reports no persona found (empty visuals, safe fallback).
|
||||
func (s *stubPersonas) Persona(string) (*loader.Persona, bool) { return nil, false }
|
||||
|
||||
// stubMemories mimics MemoryStore, returning domain memory items that the gateway
|
||||
// maps to MemorySummary.
|
||||
type stubMemories struct {
|
||||
|
||||
@@ -24,6 +24,15 @@ type PersonaSummary struct {
|
||||
IsDefault bool `json:"isDefault"`
|
||||
Mode string `json:"mode"`
|
||||
MemoryNS string `json:"memoryNamespace"`
|
||||
Avatar string `json:"avatar,omitempty"`
|
||||
// ChatBackground holds per-orientation wallpaper; a role's own, never another's.
|
||||
ChatBackground ChatBackgroundSummary `json:"chatBackground,omitempty"`
|
||||
}
|
||||
|
||||
// ChatBackgroundSummary mirrors the persona chatBackground on the wire.
|
||||
type ChatBackgroundSummary struct {
|
||||
Landscape string `json:"landscape,omitempty"`
|
||||
Portrait string `json:"portrait,omitempty"`
|
||||
}
|
||||
|
||||
// MemorySummary is the wire shape of a memory entry in the admin list response.
|
||||
@@ -199,13 +208,28 @@ func (s *Server) collectPersonas() []PersonaSummary {
|
||||
if id == "" {
|
||||
id = c.ID
|
||||
}
|
||||
out = append(out, PersonaSummary{
|
||||
sum := PersonaSummary{
|
||||
ID: id,
|
||||
Name: c.Name,
|
||||
Character: c.Name,
|
||||
IsDefault: c.Default,
|
||||
Mode: firstMode(c.Modes),
|
||||
})
|
||||
}
|
||||
// Read this persona's own visual assets (avatar / chat background). Each
|
||||
// role carries its own; a missing persona or unset visual yields empty,
|
||||
// never another role's — the frontend falls back to a neutral default.
|
||||
if p, ok := s.personas.Persona(id); ok && p != nil {
|
||||
if p.Visual.Avatar != "" {
|
||||
sum.Avatar = p.Visual.Avatar
|
||||
}
|
||||
if p.Visual.ChatBackground.Landscape != "" || p.Visual.ChatBackground.Portrait != "" {
|
||||
sum.ChatBackground = ChatBackgroundSummary{
|
||||
Landscape: p.Visual.ChatBackground.Landscape,
|
||||
Portrait: p.Visual.ChatBackground.Portrait,
|
||||
}
|
||||
}
|
||||
}
|
||||
out = append(out, sum)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ 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"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/persona/loader"
|
||||
personareg "git.yeij.top/AskaEth/Cyrene_v2/internal/persona/registry"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/knowledge"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/loop"
|
||||
@@ -89,6 +90,10 @@ type SessionStore interface {
|
||||
// domain type so the wire shape stays out of the store contract.
|
||||
type PersonaStore interface {
|
||||
List() []personareg.Character
|
||||
// Persona returns the persona with the given id (to read its visual assets).
|
||||
// The production registry implements it; the wire summary reads Avatar /
|
||||
// ChatBackground from it so each role's visuals stay role-scoped.
|
||||
Persona(id string) (*loader.Persona, bool)
|
||||
}
|
||||
|
||||
// MemoryStore lists memory entries. *runtime/memory.Store is the production
|
||||
|
||||
Reference in new issue
Block a user