feat: IM式跨端实时同步——message_persisted 广播 + 前端按id去重追加
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- history.Store 新增 AppendFull(返回含 id/createdAt 的完整消息),Append 签名不变
- session_orchestrator 加可空 OnPersisted;persistUserMessages/persistAssistantReply 落库后回调广播
- server.go newOrchestrator 接 OnPersisted → hub.broadcast message_persisted(thinking 剥除)
- 前端 ws.ts 加 message_persisted case(仅 activeSessionId 匹配才处理);appendOrUpdateMessage 升级为 id 精确upsert+内容/时间归一
- 实测:双 WS,A stream 发消息,B 免刷新收到 user+assistant 各1条(count=2 PASS)
- 红线: 身份仍靠 actor 元数据,不靠提示词;用户/助手消息、本端/异端统一路径
This commit is contained in:
Aska committed 2026-09-07 04:16:29 +08:00
1 parent bcc53d68f3
commit 1bf60c1ae4
9 files changed
+260 -38

No files matched your search

+38
View File
@@ -76,6 +76,44 @@ func TestAppendAndListNewestFirst(t *testing.T) {
}
}
func TestAppendFullReturnsID(t *testing.T) {
t.Parallel()
st := newStore(t)
ctx := context.Background()
full, err := st.AppendFull(ctx, Message{SessionID: MainSessionID, Role: RoleUser, Content: "hi"})
if err != nil {
t.Fatalf("append full: %v", err)
}
if full.ID == "" {
t.Fatal("AppendFull did not assign an id")
}
if full.CreatedAt == 0 {
t.Fatal("AppendFull did not assign a created_at")
}
if full.SessionID != MainSessionID || full.Role != RoleUser || full.Content != "hi" {
t.Fatalf("AppendFull returned %+v, want the stored message unchanged plus id/created_at", full)
}
// The message is actually persisted under the returned id.
msgs, err := st.List(ctx, MainSessionID, 0, 50)
if err != nil {
t.Fatalf("list: %v", err)
}
if len(msgs) != 1 || msgs[0].ID != full.ID {
t.Fatalf("list = %+v, want exactly the persisted message id %q", msgs, full.ID)
}
// A caller-supplied id/timestamp is preserved, not regenerated.
preset, err := st.AppendFull(ctx, Message{ID: "preset-id", SessionID: MainSessionID, Role: RoleAssistant, Content: "ok", CreatedAt: 42})
if err != nil {
t.Fatalf("append full preset: %v", err)
}
if preset.ID != "preset-id" || preset.CreatedAt != 42 {
t.Fatalf("AppendFull did not preserve preset id/created_at: %+v", preset)
}
}
func TestListPaginationBefore(t *testing.T) {
t.Parallel()
st := newStore(t)