Commit cdb7d17
feat(proactive): A/B 改测屏幕分享来源默认值 + 情境弹窗 + 娱乐 witty 语气 (Project-N-E-K-O#1513)
* feat(proactive): A/B 改测屏幕分享来源默认值 + 情境弹窗 + 娱乐 witty 语气
下线隐私默认值实验(v1/v2),改测「主动搭话里的屏幕分享来源」默认值:
- token_tracker cohort 池 → ("main", "vision_chat_default_off");老落盘值走
现有严格校验重抽机制,只改 telemetry 标签。
- 前端 A/B 覆写从「翻隐私」改成把 proactiveVisionChatEnabled 默认翻成关;
隐私模式默认值不动(仍按地区分流),海外默认隐私开 → 对本实验天然 no-op。
实验组(仅)新增情境弹窗:活动 tracker 20s 心跳检测「进游戏/娱乐」「进专注
工作」一次性事件,经 WebSocket 推前端;前端每会话每类弹一次——
- 进游戏/看番 → 问要不要开启屏幕分享搭话;
- 进专注工作 → 问要不要关掉屏幕分享避嫌(不动搭话频率,尊重用户原设定)。
检测挂在独立心跳上,隐私开时自动跳过;主动搭话默认关时由 start_session 仅为
实验组拉起心跳,控制组零额外开销。
娱乐语气补全:casual_browsing 此前与休闲游戏共用通用 playful,现拆出专属
witty(吐槽向,3 角度 ×7 语言)+「没梗就回 [PASS]」质量闸,idle 仍 playful。
i18n 补全 8 个前端 locale 的弹窗文案。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(proactive): branch 未决议时暂存情境事件待重放 + witty 质量闸回归测试
- app-context-prompt.js:branch 未决议(telemetryBranch 还没回来)时收到的
activity_context_prompt 先暂存,等 neko:telemetry-branch-resolved 再重放,避免
后端一次性「进入态」推送在分支 GET 慢时被静默丢掉、实验组漏弹窗。GET 失败则永
不重放,fail-closed。
- 补 witty 质量闸渲染回归测试(5 语言断言 [PASS] 指令出现 + 非 witty 不渲染)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(proactive): 情境弹窗暂存改为按类别缓存,避免决议前 play/work 互相覆盖
单槽 _pendingContext 在 branch 决议前先后收到 play + work 时只会留最后一个、
另一类被吞,与「每会话每类一次」语义不一致。改用 Set 按类别暂存,决议后逐类
重放。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(proactive): witty 质量闸渲染测试补 es/pt(断言回退 en 后仍有 [PASS])
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(proactive): 情境弹窗暂存重放改为串行 await,避免第二个弹窗被 _promptOpen 吞掉
分支决议前缓存了 play + work 两类时,原 forEach(handle) 并发触发:第一个 handle
开窗置 _promptOpen=true 并在 modal 上挂起,第二个 handle 撞 _promptOpen 早退、且
_pendingContexts 已 clear,导致该类弹窗本会话永久丢失。改为 for-await 串行重放,
第二个弹窗等第一个关掉再弹。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(proactive): 弹窗开着时到来的另一类 context 也暂存重放,别直接丢
handle() 在 _promptOpen=true 时原本直接 return,丢掉这次信号且不再重试——用户开着
play 弹窗时切到工作,work 信号就永久丢了。改为暂存进 _pendingContexts,当前弹窗
关掉后在 finally 里 _drainPending 串行重放。与「分支未决议」暂存复用同一 Set + 同一
串行 drain;同类重复入 Set 去重、重放时 _shownX 再拦一道。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(proactive): 控制组后端不推情境信号 + playful 改得更好接话
- 控制组(main)零回退:后端推送回调再加一道 branch gate,非实验组压根不推
activity_context_prompt(前端 _isExperimentBranch 是第二道闸)。活动 loop 在
「主动搭话已开」的 main 用户上也会跑,所以这道后端 gate 必要。
- playful 语气调整(7 语言):留钩子 / 问一句能答的小问题 / 递个好接的话头,替掉
原来「自说自话抖段子」那条容易把天聊死的角度。改动克制,保持 playful 基调。
- _drainPending 的异步重放加 .catch,防 unhandled rejection(CodeRabbit nitpick)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(proactive): 隐私模式开时不 kick 活动 tracker + branch 事件挪到设置合并后广播
- [P1] _maybe_kick_activity_loop_for_experiment 在隐私模式开(vision 关)时直接早退:
get_snapshot 会起 SystemSignalCollector 采集窗口/进程信号、绕过隐私模式(loop 只
跳过 LLM、collector 仍采)。privacy-on 的实验组本就 no-op,不 kick 即可。
- [P2] neko:telemetry-branch-resolved 从「拿到 branch 立即广播」挪到 A/B 覆写 +
server merge + saveSettings 全部落定之后。否则被缓存的 context 重放时 _isActionable
读到覆写前的旧 proactiveVisionChatEnabled,误判该不该弹。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(proactive): 重放暂存 context 按单个隔离异常,别一个抛错吞掉整批
外层 .catch 改成 for 循环内逐个 try/catch:play/work 是一次性事件,前一个 handle
意外抛错不能连累后一个不被消费(CodeRabbit)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(proactive): playful 第三角度合并「跳脱联想」+「留话头」
保留原本不错的「跳脱联想」(随性段子/天马行空联想),再叠加「落在对方好接的话头
上、别抖完就冷场」,而不是二选一。7 语言同步。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(proactive): 主动搭话关时活动 loop 跳过 activity_guess LLM,消除实验组成本回归
实验组为情境弹窗 kick 起活动 loop 后,即便用户没开主动搭话,loop 也会照常算
activity_guess 的 emotion-tier LLM 叙述——而那叙述只喂 proactive Phase 2、没消费方,
纯浪费(Codex P1)。在 loop 里、_tick_break_reminders + 情境弹窗 drain(纯规则、检测
照常)之后加一道 _proactive_chat_enabled() 闸:主动搭话关就 continue,跳过 LLM 部分。
proactive 真在跑时设置里 proactiveChatEnabled 必为 True,不误伤;fail-open。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(proactive): _proactive_chat_enabled key 缺失也 fail-open(默认 True)
key 缺失原本返回 False、和 fail-open 注释自相矛盾。改成默认 True:误判「关」会吞掉
proactive-on 用户的活动叙述(伤可见功能),误判「开」只是小成本。明确关主动搭话的
用户 key=false 照样 skip,成本修复对主流场景不变(CodeRabbit)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(proactive): 情境弹窗用独立基线 + session 开始时清,修跨 session 漏弹
tracker 跨 session 长存,_last_known_state 会带过来:上个 session 结束时在游戏、新
session 仍在游戏,state != prev_known 不成立 → 检测不到「进入」、本会话漏弹(Codex
P2)。改用 _context_prompt_last_state 专属基线(与 break/anti-slack 的 _last_known_state
隔离),新增 reset_context_prompt_baseline(),在实验组 session kick 里清一次,让当前
状态重新算作「进入」。补回归测试。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(proactive): 重置情境弹窗基线时一并清 pending,避免跨 session 推过期弹窗
reset_context_prompt_baseline 之前只清基线,没清 _context_prompt_pending:上个 session
置了 pending 但没 drain 就 end_session 时,残留会被新 session 首个 tick 推成过期弹窗
(CodeRabbit)。一并清掉,紧跟的 kick get_snapshot 会按新 session 当前状态重置。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(proactive): 口吻紧贴「决策方式」段,提升被遵循度
之前 {state_section}(含口吻)在 prompt 顶部、和底部决策段隔着对话历史+一堆素材,
口吻容易被冲淡。两步调整让口吻挨着决策规则:
- snapshot 格式化:口吻菜单 + 质量闸改到状态块**最末**渲染(在 reasons/scores/叙述/
未收尾话题之后),紧贴 ======以上为活动状态======。
- prompts_proactive 7 个 generate 模板:{state_section} 整体从 inner_thoughts 后挪到
meme_section 后、紧贴 ======以下为...决策方式======。
于是渲染顺序变成 …叙述/开放话题 → 口吻 → 质量闸 →(活动状态块结束)→ 决策方式段,
口吻就在 AI 决定怎么说时的眼前。对两组一致(非 A/B 变量)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(proactive): 离开目标状态时清掉过期情境 pending,避免推过期弹窗
pending 可能由 get_snapshot 路径(实验组 kick)置、还没等 loop drain,用户就从
游戏/工作切到 idle/away 等非目标态;之前的检测块只在进 gaming/casual_browsing/
focused_work 时 overwrite,离开时不动 pending → loop 会把已离开的场景推成过期弹窗、
甚至据此翻错设置(Codex P2)。在检测块加:state 不属于目标态就清 pending。目标态
之间切换仍由 overwrite 处理。补回归测试。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Hongzhi Wen <cartabio.coder1@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 7831326 commit cdb7d17
19 files changed
Lines changed: 843 additions & 122 deletions
File tree
- config/prompts
- main_logic
- activity
- static
- locales
- templates
- tests
- utils
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
555 | 555 | | |
556 | 556 | | |
557 | 557 | | |
558 | | - | |
559 | | - | |
560 | | - | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
561 | 566 | | |
562 | 567 | | |
563 | 568 | | |
| |||
587 | 592 | | |
588 | 593 | | |
589 | 594 | | |
590 | | - | |
591 | | - | |
592 | | - | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
593 | 603 | | |
594 | 604 | | |
595 | 605 | | |
| |||
619 | 629 | | |
620 | 630 | | |
621 | 631 | | |
622 | | - | |
623 | | - | |
624 | | - | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
625 | 640 | | |
626 | 641 | | |
627 | 642 | | |
| |||
651 | 666 | | |
652 | 667 | | |
653 | 668 | | |
654 | | - | |
655 | | - | |
656 | | - | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
657 | 677 | | |
658 | 678 | | |
659 | 679 | | |
| |||
683 | 703 | | |
684 | 704 | | |
685 | 705 | | |
686 | | - | |
687 | | - | |
688 | | - | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
689 | 714 | | |
690 | 715 | | |
691 | 716 | | |
| |||
715 | 740 | | |
716 | 741 | | |
717 | 742 | | |
718 | | - | |
719 | | - | |
720 | | - | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
| 746 | + | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
721 | 751 | | |
722 | 752 | | |
723 | 753 | | |
| |||
747 | 777 | | |
748 | 778 | | |
749 | 779 | | |
750 | | - | |
751 | | - | |
752 | | - | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
753 | 788 | | |
754 | 789 | | |
755 | 790 | | |
| |||
765 | 800 | | |
766 | 801 | | |
767 | 802 | | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
768 | 844 | | |
769 | 845 | | |
770 | 846 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1063 | 1063 | | |
1064 | 1064 | | |
1065 | 1065 | | |
1066 | | - | |
1067 | | - | |
1068 | 1066 | | |
1069 | 1067 | | |
1070 | 1068 | | |
| |||
1074 | 1072 | | |
1075 | 1073 | | |
1076 | 1074 | | |
| 1075 | + | |
| 1076 | + | |
1077 | 1077 | | |
1078 | 1078 | | |
1079 | 1079 | | |
| |||
1105 | 1105 | | |
1106 | 1106 | | |
1107 | 1107 | | |
1108 | | - | |
1109 | | - | |
1110 | 1108 | | |
1111 | 1109 | | |
1112 | 1110 | | |
| |||
1116 | 1114 | | |
1117 | 1115 | | |
1118 | 1116 | | |
| 1117 | + | |
| 1118 | + | |
1119 | 1119 | | |
1120 | 1120 | | |
1121 | 1121 | | |
| |||
1147 | 1147 | | |
1148 | 1148 | | |
1149 | 1149 | | |
1150 | | - | |
1151 | | - | |
1152 | 1150 | | |
1153 | 1151 | | |
1154 | 1152 | | |
| |||
1158 | 1156 | | |
1159 | 1157 | | |
1160 | 1158 | | |
| 1159 | + | |
| 1160 | + | |
1161 | 1161 | | |
1162 | 1162 | | |
1163 | 1163 | | |
| |||
1189 | 1189 | | |
1190 | 1190 | | |
1191 | 1191 | | |
1192 | | - | |
1193 | | - | |
1194 | 1192 | | |
1195 | 1193 | | |
1196 | 1194 | | |
| |||
1200 | 1198 | | |
1201 | 1199 | | |
1202 | 1200 | | |
| 1201 | + | |
| 1202 | + | |
1203 | 1203 | | |
1204 | 1204 | | |
1205 | 1205 | | |
| |||
1231 | 1231 | | |
1232 | 1232 | | |
1233 | 1233 | | |
1234 | | - | |
1235 | | - | |
1236 | 1234 | | |
1237 | 1235 | | |
1238 | 1236 | | |
| |||
1242 | 1240 | | |
1243 | 1241 | | |
1244 | 1242 | | |
| 1243 | + | |
| 1244 | + | |
1245 | 1245 | | |
1246 | 1246 | | |
1247 | 1247 | | |
| |||
1745 | 1745 | | |
1746 | 1746 | | |
1747 | 1747 | | |
1748 | | - | |
1749 | | - | |
1750 | 1748 | | |
1751 | 1749 | | |
1752 | 1750 | | |
| |||
1756 | 1754 | | |
1757 | 1755 | | |
1758 | 1756 | | |
| 1757 | + | |
| 1758 | + | |
1759 | 1759 | | |
1760 | 1760 | | |
1761 | 1761 | | |
| |||
1787 | 1787 | | |
1788 | 1788 | | |
1789 | 1789 | | |
1790 | | - | |
1791 | | - | |
1792 | 1790 | | |
1793 | 1791 | | |
1794 | 1792 | | |
| |||
1798 | 1796 | | |
1799 | 1797 | | |
1800 | 1798 | | |
| 1799 | + | |
| 1800 | + | |
1801 | 1801 | | |
1802 | 1802 | | |
1803 | 1803 | | |
| |||
0 commit comments