feat(backthink): 主动推送每次只发一个平台——决策渠道/最近活跃优先,平台含微信
主动推送目标不再取第一个白名单渠道(kook),也不再双目标 web+kook;改为每次只发一个平台,范围=全部已连接白名单渠道(含微信 weixin-ilink)。
backthink/push.go: pusher 单目标路由——web hint 一次 pushActive;im/auto/实体平台 hint 一次性 pushIM (msgs 置哨兵/实体平台),无 IM sink 时诚实降级 pushActive;保留 PushGate 降频与成功 RecordPush。
channelbridge/proactive.go: proactiveTarget 三级选择——①决策 [渠道:xxx] 实体平台且白名单+已连接优先;②最近活跃(主会话最近20条 newest-first 找白名单+已连接平台,web 会话自动跳过);③回退 NextConnectedAccount 用旋转游标避免永远 kook。微信不再排除、可被选中;决策 hint 指定非白名单渠道回退(不报错)。Bridge 新增 proactiveCursor 字段(mu 保护)。
context.go: guidancePrompt 描述改为每次挑一个合适渠道(含微信)。
测试: 决策优先/最近活跃/微信可选中/无信号回退旋转/单目标 等,go build/vet/test 全绿 + windows/darwin 交叉编译。stash@{0} 保留被取代的'web+kook双目标'WIP以备回滚。
This commit is contained in:
1 parent
12031bd13c
commit
3e4efa0e41
8 files changed
+419
-114
No files matched your search
@@ -170,9 +170,10 @@ func TestThink_ParsesStructuredDecision_EndToEnd(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestThink_NoMarkerDefaultRoute_ActiveFirst(t *testing.T) {
|
||||
func TestThink_NoMarkerDefaultRoute_IM(t *testing.T) {
|
||||
t.Parallel()
|
||||
// No channel marker → auto → active client first (the pre-P2 behavior).
|
||||
// No channel marker → auto → a single IM channel (the bridge picks her choice /
|
||||
// her recent platform / the whitelist default), NOT the active web client.
|
||||
conclusion := "[我决定:push]\n洗衣机洗好了,衣服可以收了"
|
||||
thinker := &mockThinker{text: conclusion}
|
||||
active := &mockActive{n: 2}
|
||||
@@ -188,18 +189,18 @@ func TestThink_NoMarkerDefaultRoute_ActiveFirst(t *testing.T) {
|
||||
|
||||
b.think(context.Background(), heartbeatTrigger())
|
||||
|
||||
if active.calls != 1 {
|
||||
t.Fatalf("active calls = %d, want 1", active.calls)
|
||||
if active.calls != 0 {
|
||||
t.Fatalf("active calls = %d, want 0 (auto targets the IM bridge, not the web client)", active.calls)
|
||||
}
|
||||
if im.count() != 0 {
|
||||
t.Fatalf("im calls = %d, want 0 (active preferred)", im.count())
|
||||
if im.count() != 1 {
|
||||
t.Fatalf("im calls = %d, want 1 (single IM target)", im.count())
|
||||
}
|
||||
recs, err := b.List(context.Background(), 10)
|
||||
if err != nil {
|
||||
t.Fatalf("List: %v", err)
|
||||
}
|
||||
if recs[0].PushResult.Route != RouteActiveClient {
|
||||
t.Fatalf("record Route = %q, want %q", recs[0].PushResult.Route, RouteActiveClient)
|
||||
if recs[0].PushResult.Route != RouteIMBridge {
|
||||
t.Fatalf("record Route = %q, want %q", recs[0].PushResult.Route, RouteIMBridge)
|
||||
}
|
||||
if recs[0].PushResult.Pushed != true {
|
||||
t.Fatalf("record Pushed = %v, want true", recs[0].PushResult.Pushed)
|
||||
|
||||
Reference in new issue
Block a user