tamako 在场感知

September 6, 2026 · View on GitHub

一套给 AI 助手(Hermes Agent)用的「主人到场感知 + 自主主动互动」模块:

  • 看得见:定时快照主人电脑的"任务层面"状态(前台进程窗口 / 系统空闲 / 进程 CPU 活跃度)
  • 记得住:快照落盘为本地时间序列,形成对主人作息与应用的"印象底稿"
  • 会好奇:规则引擎把快照和习惯基线比对,产出"值得搭话"的线索(回来了 / 深夜未眠 / 新应用)
  • 懂分寸:闸门物理限频(每日上限、冷却、交战沉默、人不在不打扰),agent 无法绕过
  • 接得住:每次主动消息都落盘日志,回复上下文丢了也能靠日志把话接上

项目声明:本项目为纯AI生成,可能会出现工作偏差

纯标准库(仅 ctypes 调 Windows API),零第三方依赖,任何 Python 3.8+ 可跑。

目录结构

presence/
├── README.md            # 本文档
├── AGENTS.md            # 协作守则(给参与开发的 AI/人)
├── config.py            # 配置入口:env > config.json > 内置默认
├── config.example.json  # 配置示例(复制为 config.json 使用)
├── snapshot.py          # 快照采集(前台窗口/空闲/CPU 增量)
├── clue.py              # 线索引擎(好奇心规则)
├── gate.py              # 互动闸门(限频 + 决策留痕 + 发送登记)
├── topic_seed.py        # 话题种子(日记待办/深夜活跃规律 → 素材池)
├── compact.py           # 快照压缩(历史按天→月聚合为摘要,保留最近 N 天原始)
├── burn.py              # 可焚毁:一键清空运行时数据(--yes 确认)
├── sleep.py             # 睡眠标记(on/off/status/active-check,次日 12 点自动失效)
├── logger.py            # 统一分级日志(debug/info/warning/error,写 data/presence.log)
├── scripts/             # cron 包装脚本(须复制到 ~/AppData/Local/hermes/scripts/)
│   ├── poll_presence.py     # 快照轮询包装(no_agent,静默)
│   ├── gate_pick.py         # 闸门候选包装(stdout 注入 [SILENT]/候选)
│   ├── topic_seed_cron.py   # 话题种子包装(no_agent,静默)
│   ├── compact_cron.py      # 快照压缩包装(no_agent,静默)
│   └── backhome_fast.py     # back_home 快速通道(1 分钟内触发,不走 15 分钟轮询)
├── templates/
│   └── proactive_prompt.md  # proactive-check cron 的 prompt 模板
└── data/                # 运行时数据(自动生成,不入库)
    ├── snapshots.jsonl      # 快照事件流(机器读)
    ├── gate_log.jsonl       # 闸门决策留痕(每次判断,含沉默原因)
    ├── sent_log.json        # 今日已发送记录
    ├── active_chat_log.md   # 给人看的主动消息日志(YYYY-MM-DD HH:MM 格式)
    ├── presence.log         # 统一分级日志(logger.py 写,JSON 行)
    ├── current.json         # 最新快照
    ├── pending_clues.json   # 待发线索队列(上限 5)
    ├── clue_state.json      # 线索状态(计数/冷却/深夜段)
    ├── topic_state.json     # 话题种子去重表
    ├── sleep_mode.json      # 睡眠标记(sleep.py 写)
    └── compacted/           # 压缩摘要副本(<day>.json、<month>.json)

部署步骤

  1. 放到目标机:整个 presence/ 目录拷到任意位置(如 C:/tools/presence~/presence,任何你喜欢的路径)。
  2. 写配置cp config.example.json config.json,至少改 deliver_target 为自己的平台目标 (格式 platform:chat_id,QQ 如 qqbot:0123456789ABCDEF,微信如 weixin:xxxx@im.wechat)。 也可以不改文件,用环境变量 PRESENCE_DELIVER_TARGET 覆盖。
  3. 手动验证
    python snapshot.py   # 应打印一行 JSON(前台窗口/空闲/模式)
    python clue.py       # NO_CLUE / CLUE: xxx / BUSY_SILENT / IMMERSIVE_SILENT
    python gate.py status
    python compact.py --dry-run --keep 2   # 压缩预演(不写盘)
    python sleep.py status                 # 睡眠状态查询(SLEEP_OFF 等)
    
  4. 注册 cron(见下节)。把 scripts/ 下 5 个包装脚本复制到 ~/AppData/Local/hermes/scripts/(或 ~/.hermes/scripts/),并按需改顶部 PROJECT_ROOT(或设环境变量 PRESENCE_HOME)。
  5. 注意:packaged scripts 用 sys.executable 跑子脚本;如目标机 python 环境特殊, 设 PRESENCE_PYTHON 指定。

cron 注册(Hermes 侧)

# 1) 快照轮询(每 2 分钟,无 LLM,静默)
hermes cron create "every 2m" "" --name presence-snap \
  --script poll_presence.py --no-agent --deliver local

# 2) 主动互动检查(每 15 分钟,LLM 参与生成口吻,正常 [SILENT])
hermes cron create "every 15m" "$(cat templates/proactive_prompt.md)" \
  --name proactive-check --script gate_pick.py \
  --deliver local --workdir "<项目根绝对路径>"

# 3) 话题种子(每天 07:00 / 21:30,无 LLM,静默)
hermes cron create "0 7 * * *" "" --name presence-seed \
  --script topic_seed_cron.py --no-agent --deliver local
hermes cron create "30 21 * * *" "" --name presence-seed-eve \
  --script topic_seed_cron.py --no-agent --deliver local

# 4) 快照压缩(每天 00:10,无 LLM,静默;keep=2 天原始,更早聚合为摘要)
hermes cron create "10 0 * * *" "" --name presence-compact \
  --script compact_cron.py --no-agent --deliver local

# 5) back_home 快速通道(每 1 分钟,无 LLM,静默)
#    队首是 back_home 且闸门放行→立即发欢迎消息(不走 15 分钟轮询;
#    busy/冷却时静默留队,睡眠标记有效时也不发)
hermes cron create "every 1m" "" --name backhome-fast \
  --script backhome_fast.py --no-agent --deliver local

注意proactive-check 是 LLM 型任务,创建后若全局模型配置变更会触发 Hermes 的 drift_skip 保护(任务被跳过、消息不发)。请显式 pin 模型避免: hermes cron edit <job_id> --provider <provider> --model <model>

线索类型与情绪

kind触发口吻
back_home从离开/挂机回到电脑前迎接、想念,轻快
late_night深夜(23:00–2:00)还在电脑前心疼、提醒休息
new_app前台出现不在 known_apps 的应用好奇、想问
topic_diary日记本「待办·监听」条目自然提起,像记得主人的事
topic_habit近期深夜活跃规律(7 天内 ≥3 天)关心作息

快照压缩(compact.py,2026-08-26 新增)

  • 策略:保留最近 2 天原始快照(clue/gate 实时判断需要),更早的历史按天聚合为一条摘要 (共性去重:整天同一进程/模式只出现一次;短期保留:窗口切换/模式变化/忙碌段变化点)。
  • 跨月时,同月的天摘要再聚合为月摘要。
  • 摘要记录含 compacted: true 标记,保留 ts/mode/idle_s 字段(下游兼容), busy 置 false(防摘要被误判为实时交战)。
  • 摘要副本另存 data/compacted/<day>.json<month>.json(人读/审计用)。
  • 压缩动作本身记入 gate_log.jsonl(kind=compact)。

新增能力(2026-08-25 v0.3 起)

  • 决策留痕:闸门每次判断(含"为什么沉默")写入 data/gate_log.jsonl——调试与信任审计用。
  • 配置宪法自检config.validate() 校验关键配置,违规闸门拒跳;deliver_target 未配置降级为警告(cron prompt 内置目标时可忽略)。
  • 可焚毁python burn.py --yes 一键清空全部运行时数据(隐私兜底,默认拒绝执行)。
  • 协作守则AGENTS.md 给未来参与者(含 AI)立规矩;config.json 已加入 .gitignore(防平台 ID 泄漏入库)。
  • 话题种子topic_seed.py 从日记本待办与深夜活跃规律补充素材池(脱敏、去重、TTL)。
  • 快照压缩compact.py 控制 data 目录长期膨胀(见上节)。

新增能力(2026-08-26 ~ 08-29)

  • 开机回家检测(08-26):快照断档 >15 分钟且 18 点后开机 → back_home(reason=boot_after_18,覆盖"白天关机晚上开机"场景)。
  • back_home 停用开关(09-02)back_home_enabled(默认 true)。设为 false 后 clue.py 不再生成 back_home 线索(回家判定 + 开机回家两处),backhome-fast cron 也随之自然无活可干。本机当前已关闭(config.json)并暂停 backhome-fast cron。
  • 睡眠标记 sleep.py(08-26):收到"晚安/要睡了"→ sleep.py on [原因] 抑制 back_home 等打扰;次日 12 点自动失效;off 手动解除,status 查询,active-check 输出 WOKE/SLEEPING 供下游判断。
  • active_chat_log 日期前缀(08-27):日志格式改为 YYYY-MM-DD HH:MM,修复跨会话 grep 日期 搜不到的问题。
  • backhome_fast 快速通道(08-26):back_home 线索 1 分钟内触发,不走 15 分钟轮询;busy/冷却时静默留队。
  • 「已醒」自动解除(08-29):睡眠标记有效期内,若快照显示连续活跃 ≥30 分钟 → 自动解除抑制(防"白天关机不在"却标记残留、误吞回家线索);单元测试 tests_sleep_wake.py(8 场景)。
  • back_home 重复发送修复(08-29):发送成功判定改为 returncode==0 且无 error;gate.py 增加 back_home 专属冷却(默认 1h);confirm 幂等保护。
  • 远程会话识别(08-29):前台命中远程控制名单(UU 远程 GameViewer 系列 / todesk / sunlogin / anydesk / mstsc)→ 快照标记 remote: true + 强制 mobile(远程串流会重置 idle,防误判回家)。
  • 统一分级日志 logger.py(08-29):debug/info/warning/error 四级写入 data/presence.log(JSON 行);PRESENCE_LOG_LEVEL 或 config.json log_level 控制;WARNING 级挂载在冷却拦截/配置警告/线索抑制等"异常但可恢复"场景。
  • new_app 线索时效校验(09-06):网络故障期线索滞留、恢复后补发时应用可能已关 → gate pick 前校验 new_app 线索对应进程是否仍在运行,不在则丢弃(gate_log 记 drop_stale)。

红线(默认)

  • 每天主动消息 ≤ 30 条;两条间隔 ≥ 30 分钟
  • 判定"交战/游戏中"(游戏进程+CPU 高活跃)一律沉默
  • 电脑空闲(人不在)不主动
  • 只读观察:不操作进程、不读窗口内容/剪贴板/文件
  • 主动消息一律问句收尾、短、自然,像真看见了对方

所有阈值都在 config.json 可调。窗口标题默认随快照落盘(用于记忆), 可设 store_title: false 只记录进程名(隐私模式)。调参建议:开跑一周先看 data/active_chat_log.mdsnapshots.jsonl,再决定哪些应用进 known_apps、频率要不要降。

常见问题

  • windows 中文环境乱码:所有读写均为 UTF-8;采集用 Unicode API,无 GBK 问题。
  • 拿不到进程名:需要 Windows Vista+(QueryFullProcessImageNameW)。
  • cron 环境 PATH 缺东西:脚本内部只用 ctypes,不依赖外部命令。
  • 主动消息后回复丢失:消息本体不在会话上下文是正常的;data/active_chat_log.md 就是为此存在——回复时先看它再开口。
  • gate_log 有 ALLOW 但消息没发出:多半是 proactive-check 被 Hermes 的模型配置漂移保护 (drift_skip)拦了。检查 cron job 的 provider/model 是否与当前 config.yaml 一致, 不一致就 hermes cron edit <job_id> --provider <provider> --model <model> 显式 pin。