feat(channels): 管理面板消息日志——chat_messages 加 adapter_id + 配置级/平台/总览三粒度端点
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

后端:
- 迁移 0007:chat_messages 加 adapter_id 列 + 索引
- history.Message 加 AdapterID;persistToMain/persistIsolated 传适配器名(a.Name())
- channelbridge: 4 个持久化点 + registerSilenced 传 a;light.go registerSilenced 签名加 a
- Store 新增 ListAdapterLog(?adapter=, 不排除主会话)/ListAllLog(adapter_id!='', 总览);ListPlatformLog 保留
- 新端点 GET /api/v1/admin/channels/messages:?adapter= 配置级 / ?platform= 平台 / 无参=总览,historyMessage 加 adapterId
- 测试:ListAdapterLog/ListAllLog 过滤用例 + 端点粒度用例 + 桥接持久化断言

前端:渠道管理每配置(账号)「消息日志」按钮 + 页顶「适配器总览日志」入口 + ChannelLogPanel 弹窗(总览/配置级),Miuix 风格,build 绿。
This commit is contained in:
Aska committed 2026-09-07 17:25:23 +08:00
1 parent c1bd740f7c
commit 2e044d1d19
15 files changed
+560 -41

No files matched your search

@@ -255,6 +255,12 @@ func (c *captureHistory) Recent(context.Context, string, int) ([]history.Message
func (c *captureHistory) ListPlatformLog(context.Context, string, int64, int) ([]history.Message, error) {
return nil, nil
}
func (c *captureHistory) ListAdapterLog(context.Context, string, int64, int) ([]history.Message, error) {
return nil, nil
}
func (c *captureHistory) ListAllLog(context.Context, int64, int) ([]history.Message, error) {
return nil, nil
}
func (c *captureHistory) DeleteSession(context.Context, string) error { return nil }
func (c *captureHistory) NewSubSession(context.Context, string) (string, error) {
return "", nil
@@ -284,6 +290,9 @@ func TestOwnerPrivatePersistsToMainSessionWithPlatform(t *testing.T) {
if err != nil {
t.Fatalf("New: %v", err)
}
// Register the account adapter that pretends to receive the message, so the
// persisted stream carries the adapter registration name (e.g. "telegram").
b.Add(&fakeAdapter{name: "telegram"})
msg := directMessage() // Platform = "telegram"
b.process(context.Background(), msg)
@@ -292,14 +301,14 @@ func TestOwnerPrivatePersistsToMainSessionWithPlatform(t *testing.T) {
if len(recs) != 2 {
t.Fatalf("appends = %d, want 2 (user + assistant)", len(recs))
}
// Both land on the main web session and carry the channel platform.
// Both land on the main web session and carry the channel platform + adapter.
if recs[0].SessionID != history.MainSessionID || recs[0].Role != history.RoleUser ||
recs[0].Content != "hello" || recs[0].Platform != "telegram" {
t.Fatalf("user record = %+v, want web/telegram/hello", recs[0])
recs[0].Content != "hello" || recs[0].Platform != "telegram" || recs[0].AdapterID != "telegram" {
t.Fatalf("user record = %+v, want web/telegram/hello/telegram", recs[0])
}
if recs[1].SessionID != history.MainSessionID || recs[1].Role != history.RoleAssistant ||
recs[1].Content != "微信回复" || recs[1].Platform != "telegram" {
t.Fatalf("assistant record = %+v, want web/telegram/微信回复", recs[1])
recs[1].Content != "微信回复" || recs[1].Platform != "telegram" || recs[1].AdapterID != "telegram" {
t.Fatalf("assistant record = %+v, want web/telegram/微信回复/telegram", recs[1])
}
// Every persisted message was handed to the broadcast hook.
if len(persisted) != 2 {