feat(persona,web): 人格读侧(thinking 三态 + 角色级 mood)+ 面板表单 + mood 播种
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

按 design/04 §3.2(thinking 语义,showToUser 三态)+ design/01 §2.1 + 主人两条定论(心情跟角色不跟会话;mood 初值走口径 ①:由角色读端点暴露、前端加载播种)。
- 管理侧 GET /admin/personas 的 PersonaSummary 增 thinking(budgetTokens/effort/mode/showToUser)——**showToUser 保持三态**(未配置 ≠ false)
- 用户侧 GET /personas 增**角色级 mood**(取自 emotion 层该角色当前状态,非从消息推断)→ 前端加载播种 currentMood,消除「刷新后心情徽标短暂为空」
- 前端 Personas 页加 thinking 四控件(预算/effort/模式/showToUser 三态):只做输入校验,**provider 是否真支持由后端 WARN 决定,前端不假装能力**
- 先拆 useAppStore 选择器(原 494/500)到独立模块再做,避免越线
- Docs/api-client 版本号 +1(两处契约 + 三态与角色级 mood 语义)
- 验收:go build/vet/test 全绿 + linux/darwin 交叉编译 + 前端 build 绿 + personaSession/messageSync 逻辑测试通过
This commit is contained in:
AskaEth committed 2026-10-03 20:40:44 +08:00
1 parent 6dc1f218d5
commit 2aa3233f84
20 files changed
+1042 -61

No files matched your search

@@ -100,7 +100,7 @@ func (s *Server) adminCreatePersona(w http.ResponseWriter, r *http.Request) {
return
}
s.auditClaims(r, "persona.create", "ok")
writeJSON(w, http.StatusCreated, personaSummaryOf(p, characterFromRequest(req)))
writeJSON(w, http.StatusCreated, s.personaSummaryOf(p, characterFromRequest(req)))
}
// adminUpdatePersona edits an existing persona, persisting the YAML and
@@ -157,7 +157,7 @@ func (s *Server) adminUpdatePersona(w http.ResponseWriter, r *http.Request) {
return
}
s.auditClaims(r, "persona.update", "ok")
writeJSON(w, http.StatusOK, personaSummaryOf(p, characterFromRequest(req)))
writeJSON(w, http.StatusOK, s.personaSummaryOf(p, characterFromRequest(req)))
}
// adminCreateUser answers honestly: there is no persistent user table and no
@@ -300,8 +300,11 @@ func characterFromRequest(req personaUpsertRequest) *personareg.Character {
return &personareg.Character{ID: req.ID, Name: req.Name, PersonaID: req.ID, Modes: modes}
}
// personaSummaryOf maps a persona+character to its wire summary.
func personaSummaryOf(p *loader.Persona, c *personareg.Character) PersonaSummary {
// personaSummaryOf maps a persona+character to its wire summary. It is the same
// shape the admin list returns — the role-level mood plus the `thinking` block —
// so a write response and a subsequent read describe the persona identically
// (a client can trust either for backfill).
func (s *Server) personaSummaryOf(p *loader.Persona, c *personareg.Character) PersonaSummary {
return PersonaSummary{
ID: p.ID,
Name: c.Name,
@@ -309,6 +312,8 @@ func personaSummaryOf(p *loader.Persona, c *personareg.Character) PersonaSummary
IsDefault: c.Default,
Mode: firstMode(c.Modes),
MemoryNS: p.MemoryNamespace(),
Mood: s.moodOf(p.ID),
Thinking: thinkingSummaryOf(p.Thinking, true),
}
}