尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

gbrain 静默时段与跨时区通知门控实战:Quiet Hours 机制、滞留消息汇入晨报与自动时区感知

gbrain 静默时段与跨时区通知门控实战:Quiet Hours 机制、滞留消息汇入晨报与自动时区感知 gbrain 静默时段与跨时区通知门控实战Quiet Hours 机制、滞留消息汇入晨报与自动时区感知【免费下载链接】gbrainGarrys Opinionated OpenClaw/Hermes Agent Brain项目地址: https://gitcode.com/gh_mirrors/gb/gbrain导读深夜 3 点被 cron 任务的通知吵醒一次用户就可能直接禁用整套通知系统——这是安静时段Quiet Hours机制要解决的信任问题。本文以 gbrain 的 quiet-hours.md 为骨架完整讲解如何让大脑在夜间继续工作dream cycle、collectors、enrichment同时把通知滞留到次日清晨汇入晨报当用户旅行到东京时系统还能从日历自动推断时区、零配置调整投递窗口。读完你将掌握安静时段门控的实现模式含 shell 脚本、滞留消息的拾取机制、时区感知的操作状态设计以及 gbrain 中两处原生支持 quiet hours 的钩子自升级与 Minion 队列并能用仓库源码验证每一条行为。一、为什么需要 Quiet Hours一次 3 AM 通知的信任危机gbrain 的生产部署通常挂着 20 多个周期性任务见 cron-schedule.md每 30 分钟的邮件监控、X/Twitter 采集、每日多次的会议同步、每周的日历同步、每日早晨的 briefing、每周的大脑维护、每晚的 dream cycle。这些任务大部分在后台安静地运行但任何产生通知的任务在用户睡觉时触发都会造成打扰。文档给出的核心判断是没有 Quiet Hourscron 任务在凌晨 3 点推送 ping。一次糟糕的通知就足以让用户禁用整个系统。有 Quiet Hours大脑通宵工作dream cycle、collectors、enrichment 照常运行但通知被滞留到早晨用户飞往东京时系统从日历自动调整无需任何配置修改。这本质上是一条信任边界安静时段保护的是用户对智能体不会在错误时间打扰我这一契约的信任。它不该成为功能开关而应是每个产生通知的 cron 任务的前置强制门控。二、Quiet Hours Gate通知前的第一道检查2.1 判定逻辑安静时段门控的核心是一个极简的本地小时判定QUIET_START 23 // 11 PM local time QUIET_END 8 // 8 AM local time is_quiet(local_hour): return local_hour QUIET_START OR local_hour QUIET_END在发送任何通知之前必须依次完成三步确定用户当前时区来自配置或 heartbeat 状态将当前 UTC 时间转换为用户本地时间若处于安静时段滞留消息不发送。注意这里跨越午夜的窗口23 点到次日 8 点用 QUIET_START OR QUIET_END表达——这种包裹午夜的判定是安静时段最容易写错的地方gbrain 在源码里也专门处理了这一点。2.2 源码印证Minion 的 claim-time 门控gbrain 的 Minion 队列系统把同样的判定抽象成了纯函数位于 src/core/minions/quiet-hours.ts。其中evaluateQuietHours()的判定逻辑与原文档的伪代码一一对应且处理了两种窗口形态export function evaluateQuietHours( cfg: QuietHoursConfig | null | undefined, now: Date new Date(), ): QuietHoursVerdict { if (!cfg) return allow; if (!isValidConfig(cfg)) return allow; const hour localHour(now, cfg.tz); if (hour null) return allow; // unknown tz → fail-open const inWindow cfg.start cfg.end ? hour cfg.start hour cfg.end : hour cfg.start || hour cfg.end; // wrap-around if (!inWindow) return allow; return cfg.policy skip ? skip : defer; }几个值得注意的实现细节wrap-around窗口{start: 22, end: 7}表示 22 点到次日 7 点比较器同时处理直线窗口与跨午夜窗口源码注释明确写了这一点fail-open 设计时区未知或配置非法时返回allow避免因为配置错误而阻塞所有任务——safer than hard-blocking every job配置校验isValidConfig()要求start/end是 0–23 的整数、两者不能相等零宽窗口视为歧义、tz必须是非空字符串本地小时获取localHour()用Intl.DateTimeFormat配合 IANA 时区计算并处理了某些 Node/Bun 版本在午夜时返回24的边界n % 24兜底。更重要的是门控时机源码文件头注释强调evaluated at claim time, not dispatch在任务认领时判定而非派发时。原因是派发时判定是错误的——一个在安静时段外排队、却在安静时段内变得可认领的任务必须在 worker 每次问我现在能跑吗时重新对照当前墙钟检查。这个claim-time enforcement的修正来自 CEO review 的 codex correction是整个门控正确性的关键。Minion 门控返回三种判定QuietHoursVerdict判定含义行为allow不在安静窗口内任务可运行skip处于skip策略的安静窗口丢弃该事件defer处于defer策略的安静窗口重新入队稍后运行策略默认是defer重新排队只有当配置显式指定policy: skip时才丢弃。这个策略字段是原文档伪代码之外、gbrain 原生实现补充的关键设计——通知类任务与后台任务对滞留的语义需求不同。2.3 三个判定输入的正确顺序文档的伪代码与源码共同勾勒出正确的执行顺序读取配置/状态中的quiet_hours或self_upgrade.quiet_hours与用户时区用localHour(now, tz)得到本地小时gbrain 源码提供了可直接复用的实现判定窗口内/外窗口内则按策略 skip 或 defer对 cron 通知场景即滞留到 held 目录。三、Held Messages滞留消息与晨报拾取3.1 写入 held 目录安静时段内输出不发送而是写入滞留目录if is_quiet(): mkdir -p /tmp/cron-held/ write(/tmp/cron-held/{job-name}.md, output) exit // dont send else: send(output)3.2 晨报拾取早晨 briefing 读取滞留目录把内容折叠进晨报morning_briefing(): held_files list(/tmp/cron-held/*.md) if held_files: briefing ## Overnight Updates\n\n for file in held_files: briefing read(file) delete(file)这样没有任何信息丢失通宵的 cron 结果成为用户早晨第一眼看到的内容。gbrain 的 briefing skill 是这套晨报能力的技能化载体其调度见 cron-schedule.md 中 Daily AM 的 Morning briefing 行。3.3 持久化注意事项/tmp在重启后不保留macOS 还会有周期性清理。如果滞留消息必须跨重启存活应使用持久目录例如~/.local/state/cron-held/。文档在Tricky Spots中特别提示滞留目录的孤儿文件意味着拾取集成坏了——如果晨报不读/tmp/cron-held/隔夜结果会静默消失必须验证 briefing 技能确实读取并清空滞留目录。四、Timezone Awareness时区感知的操作状态4.1 操作状态结构Agent 应知道用户所在的时区并存储在操作状态operational state中{ userAwake: true, currentLocation: { timezone: Europe/Zurich, city: Basel, source: user-confirmed }, homeLocation: { timezone: Europe/Zurich, city: Basel } }homeLocation是可选的。上下文引擎只有在显式 home 时区与当前时区不同时才显示一个独立的home 时钟它从不猜测home 城市或时区。garryAwake别名保留以兼容旧数据生产者应写入userAwake。这条字段迁移在源码中得到了印证src/core/context-engine.ts 的HeartbeatState接口中userAwake/userAwokeAt是正式字段而garryAwake/garryAwokeAt被显式标记为deprecatedKept for existing heartbeat-state files。currentLocation与homeLocation都基于LocationState结构city/state/province/country/timezone/source/note。4.2 上下文引擎中的安静时段判定更值得注意的是上下文引擎把安静时段提升为**实时上下文Live Context**的一部分相关类型同样定义在 src/core/context-engine.ts 中/** Whether the user has flagged themselves awake (heartbeat.userAwake). */ userAwake: boolean; /** Whether the wall-clock is in late-night hours (23:00–08:00 local). FALSE when timezone is unknown. */ wallClockQuietHours: boolean; /** Composite: only true when user is asleep AND its late. FALSE when timezone is unknown. */ quietHoursActive: boolean; activeTravel: string | null;wallClockQuietHours直接实现了文档的is_quiet()语义23:00–08:00 本地时间quietHoursActive是复合判定只有当用户明确标记为睡着userAwake: false且墙钟确实处于深夜时才为 true——即用户睡着 AND 时间很晚时区未知时这些字段强制为false宁可低估安静状态也不在错误时区下误判。4.3 旅行时的时区更新时机文档要求在这些时机更新时区日历显示用户正在飞行检查航班/酒店事件用户提到身处不同城市用户的活跃时段发生偏移凌晨 3 点 PT 还在回复 很可能在旅行。所有展示给用户的时间都必须是其本地时区绝不显示 UTC 或用户不在的时区。gbrain 在 cron-schedule.md 中给出一个可操作的get_user_timezone()模式先gbrain search flight --type calendar --recent 7d查近期航班命中则用目的地推断时区否则回退到config.default_timezone如 US/Pacific。上下文引擎对旅行时区有更严格的源码级处理内置的AIRPORT_TZ表把常见机场代码映射到 IANA 时区如NRT/HND→Asia/Tokyo、SFO→US/Pacific而未收录机场会返回UNKNOWN_TZ哨兵值——此时引擎宁可输出显式的timezone unavailable警告也不在错误的时区下算出自信但错误的本地时间。这是该引擎要阻止的失败类别注释中明确写为 pre-v0.32.5 的修复。4.4 旅行场景的端到端效果用户飞往东京的例子太平洋时间下午 2 点 东京时间凌晨 3 点 安静时段。此时本应发送的通知被滞留折叠进下一次晨报。用户在家的活跃时段出发的 cron 任务、在目的地的睡眠时段触发时全部自动滞留——零配置修改。五、Shell 实现可复用的 quiet-hours-gate.sh对于 gbrain 不原生门控的自有 cron 任务、collector、通知路径文档给出了完整的 shell 门控脚本#!/bin/bash # quiet-hours-gate.sh — run before any notification TIMEZONE${USER_TIMEZONE:-US/Pacific} LOCAL_HOUR$(TZ$TIMEZONE date %H) if [ $LOCAL_HOUR -ge 23 ] || [ $LOCAL_HOUR -lt 8 ]; then echo QUIET_HOURStrue exit 1 # dont send fi echo QUIET_HOURSfalse exit 0 # ok to send关键设计点时区通过USER_TIMEZONE环境变量注入缺省回退US/PacificTZ$TIMEZONE date %H直接以目标时区取本地小时无需任何时间转换工具用退出码作为门控信号0 可发送1 安静时段方便在 shell 条件中直接使用。在 cron 任务脚本中的调用方式# Check quiet hours first if ! bash scripts/quiet-hours-gate.sh; then mkdir -p /tmp/cron-held echo $OUTPUT /tmp/cron-held/$(basename $0 .sh).md exit 0 fi # Not quiet hours — send normally send_notification $OUTPUT注意$(basename $0 .sh).md用脚本名生成滞留文件名保证每个任务的滞留消息互不覆盖。这套模式与 cron-schedule.md 中Quiet Hours Gate (MANDATORY)一节的描述一致——该文档明确指出门控脚本需要你自己创建gbrain 不自带并指引以 quiet-hours.md 为唯一权威来源不要复制片段。六、GBrain 原生 Quiet Hours 钩子先查再自建在为自己编写门控脚本之前先确认 gbrain 是否已原生门控同一任务。文档明确列出两处6.1 自升级Self-upgradeauto 模式只在安静时段内生效auto模式gbrain config set self_upgrade.mode auto只在安静时段内静默应用升级配置键为gbrain config set self_upgrade.quiet_hours {start:23,end:8,tz:US/Pacific}详见 upgrades-auto-update.md。源码印证在 src/core/self-upgrade.ts 的decideSelfUpgrade()纯决策函数中autopilot 通道静默自动升级的门控顺序清晰可见——idle检查大脑空闲、inQuietHours检查在安静时段内、canSelfUpdate检查安装方式支持自升级任一不满足都会返回带原因的 no-op 动作。其中安静时段相关动作类型为outside_quiet_hoursreason: outside quiet hours配置结构为quiet_hours?: { start?: number; end?: number; tz?: string }。这意味着**安静时段才动用户环境是 gbrain 升级机制的硬性安全约束**与本文的通知门控共享同一套时段概念。6.2 Cron Prompts / Minion 队列调度驱动的通知任务应携带本文描述的门控调度的另一侧排期本身见 cron-schedule.md。而 gbrain 的 Minion 队列gbrain jobs通过 src/core/minions/quiet-hours.ts 在任务认领时原生执行allow/skip/defer判定见第二节配置结构与self_upgrade.quiet_hours一致start/end/tz外加可选policy。其余一切场景——你自己的 cron 任务、collector、gbrain 不替你门控的通知路径——才使用第五节中的 shell 模式。七、可配置时段quiet_hours 配置结构不同用户有不同的安静时段需求配置存储结构如下{ quiet_hours: { start: 23, end: 8, enabled: true } }start/end本地小时0–23支持跨午夜窗口如 22–7enabled: false完全禁用安静时段例如 24/7 监控场景。在 gbrain 原生实现中这个结构对应QuietHoursConfig见 src/core/minions/quiet-hours.tsstart为窗口起始本地小时含、end为窗口结束本地小时不含、tz为 IANA 时区、可选policy取skip或defer默认defer。注意文档 JSON 里的enabled与源码的policy是两个层面enabled控制整段时段是否生效policy控制窗口内事件是丢弃还是重排。八、Tricky Spots四个最容易翻车的坑每个任务都必须过门控。安静时段检查必须运行在每一个会产生通知的 cron 任务之前。哪怕只有一个任务跳过门控用户就会收到 3 AM ping从而失去对整个系统的信任。无例外。滞留消息必须被拾取。如果晨报不读取/tmp/cron-held/隔夜结果会静默消失。必须验证 briefing 技能读取并清空滞留目录滞留目录出现孤儿文件 拾取集成已损坏。/tmp不持久。/tmp在重启后不保留macOS 还有周期性清理。需要跨重启保留的滞留消息应使用持久目录例如~/.local/state/cron-held/。时区自动检测是脆弱的。基于日历的时区检测依赖用户行程中有带位置数据的航班/酒店事件。如果用户不写日历就出行系统无法感知。应回退到活跃时段分析凌晨 3 点 PT 还在回复 大概率已不在 PT仍不确定时就直接询问用户。九、如何验证三组可复现的测试步骤9.1 验证安静时段滞留将QUIET_START临时设为当前时间前 1 小时、QUIET_END设为当前时间后 1 小时。触发一个 cron 任务验证输出进入/tmp/cron-held/而非被发送。9.2 验证滞留消息拾取接上一步运行或模拟晨报。验证滞留消息出现在 Overnight Updates 段落中且/tmp/cron-held/中的文件已被删除。9.3 验证时区调整将时区配置改到当前正处于安静时段的时区触发通知验证被滞留改回真实时区处于活跃时段再次触发验证正常发送。这个闭环同时覆盖了时区判定与门控决策两条路径。结语Quiet Hours 的正确打开方式安静时段机制的全部要点可以浓缩为三条纪律门控必须前置且无死角每个通知任务、在认领时刻重新判定滞留必须可拾取晨报读取并清空否则信息静默丢失时区必须感知且 fail-safe未知时区宁可 fail-open 或显示警告绝不输出错误时区下的自信时间。gbrain 的源码实现——src/core/minions/quiet-hours.ts 的 claim-time 门控与 wrap-around 窗口处理、src/core/context-engine.ts 的quietHoursActive复合判定与UNKNOWN_TZ哨兵、src/core/self-upgrade.ts 的outside_quiet_hours门控——为这套模式提供了可直接对照甚至直接复用的实现。你的 cron 任务只需一行门控检查就能在用户睡觉时继续干活、醒来时安静汇报。本文基于 GBrain Skillpack 中的 quiet-hours.md 展开相关文档还包括 cron-schedule.md 与 upgrades-auto-update.md。【免费下载链接】gbrainGarrys Opinionated OpenClaw/Hermes Agent Brain项目地址: https://gitcode.com/gh_mirrors/gb/gbrain创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表