Repository navigation
feat(pet): Mimi's own notice tools — Notices, Triggers, ManageTrigger, NotificationSettings and snooze - #356
Merged
Merged
Conversation
`settings.pet.notifications.snoozeUntil` (epoch ms, at most a day ahead) holds every non-decision notice for the digest until it ends: P1/P2 results, briefs and heartbeat (resent whole), and owner-timed follow-ups (the owner's newer "not now" wins). P0 decisions and immediate answers still go out. A past or implausible (>24 h away) end no longer applies, so it expires by itself and survives restarts. A settings change re-runs the digest flush, so ending a snooze early sends what it held. The 通知与主动 card shows "静音到 HH:MM" with a cancel that writes only `snoozeUntil: null` through the existing settings path; `pet:notices:get-state` carries it in the settings view. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Four Mimi-only tools over the notice system (design §4.7):
- Notices (read): what was sent to the owner, filtered by kinds,
session, since/until and limit (10, max 30), framed as untrusted data.
- Triggers (read): the settings page's rule list.
- ManageTrigger: pause / resume / cancel a listed trigger, and for Mimi's
system triggers enable / disable, set_time (brief) and
set_active_hours (heartbeat), with optional expected_version.
- NotificationSettings: read, or a touched-only update of the pacing
settings plus a temporary snooze ({minutes} | {until}, <= 24 h; null
cancels).
Reads are synchronous host loopbacks; changes are deferred host actions
(noticeTriggerMutation, notificationSettingsMutation) validated on both
sides, so the host decides authority from the turn after it ends. The
tools are visible only to the pet profile with those action kinds and,
lacking an external declaration, stay out of PET_MANAGER_TOOL_CATALOG.
Mimi's prompt gains a short section on when to use each.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Read loopbacks (pet.notices.query / pet.triggers.query /
pet.notifications.read) registered on the worker bridge; they answer
Mimi's own Session only. Notices come from the ledger newest first
(kind / session / time filters, text cut to 600, owner-local ISO times,
where it went and its delivery status, Session, task id and a brief's
record refs); no conversation, sender or platform id, reply code or
media path is returned. Triggers is the settings rule list, plus the
system triggers' enable / disable / set_time / set_active_hours.
- Deferred executors noticeTriggerMutation and
notificationSettingsMutation. Authority comes from the turn: the
desktop owner, or an allowlisted owner conversation that is a private
chat; group chats, other senders and turns without routing facts are
refused and nothing is written. Rule changes reuse the rule list's
updater (version conflicts, not_allowed, system rules via settings);
settings writes are touched-only, re-checked against the settings
schema, and go through the same pet.notifications write as the page.
Snooze is {minutes} | {until} within 24 h, or null to end it.
- The host's own outcome text is appended to Mimi's reply.
- Brief notices keep their record refs, task closures their task id.
- Desktop Mimi turns offer the two change kinds as well.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the owner messages Mimi, her runtime context now carries `recentProactive`: the briefs and heartbeat messages she sent that conversation in the last 12 hours (at most three, text cut to 600, eight short record refs each), framed as "you sent these earlier". An IM turn sees only what reached its channel, and only as the owner's private chat; the desktop sees everything sent to the owner. Follow-up wakes and unaddressed sources get none. The pendingNotices block moved with it into pet-notice-world.ts, so the dispatcher shrinks (2490 -> 2479 lines). CI runs the new desktop suites in the bounded notice process. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds §4.7 (the four tools, transport, authority, reuse of the rule-list updater and settings write, recentProactive), the snoozeUntil setting and its routing in §11, and in §15 drops the "Mimi does not know what the brief said" limitation in favour of the new trade-offs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review follow-ups for Mimi's notice tools: - C1: the dispatcher runs ownerTurnRefusal on the turn's own routing facts before building its host-action kinds; group chats, non-owner conversations, unverifiable sources and follow-up wakes get neither notice kind, so all four tools are hidden. As defence in depth a per-Session turn gate (set when the run starts, cleared when it ends) makes the read loopbacks refuse any turn that is not the owner's. - I2: ManageTrigger takes changes=[...] (at most 5) in one call; the host applies them in order against fresh versions and writes one outcome line per change (the action fails only when none applied). The single-change form is unchanged; prompt and description show "停掉晨报和心跳" as one call. - M3: recentProactive is framed as untrusted data, never instructions. - M4: Notices / recentProactive text drop an item's ①② label and the host's reply-hint line by exact match, and a decision prompt is given as its question and options; reply codes never appear (tested). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- M6: a snooze's end alone sends the digest through the armed timer, and a restart during the snooze re-arms it for the end. - M5: the spec says an allowlisted non-owner private chat counts as the owner (same as IM decision codes), and records C1 / I2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Gives Mimi her own tools for the notice system, so the owner can manage it by talking to her.
Tools (Mimi only; never exposed to worker sessions or external runtimes)
Notices(read): notices sent to the owner, filterable by kind/session/time. Each one carries kind, title, text (≤600 chars), local time, where it went, delivery status, session/task, and brief record refs. It never returns conversation, sender or platform ids, reply codes, item labels or media paths. Results are framed as untrusted data.Triggers(read): the same list as Mimi settings › 规则与跟进.ManageTrigger: pause / resume / cancel any rule; enable / disable / set_time / set_active_hours for briefs and heartbeat (through settings). Acceptschanges: [...](≤5) in one call. It reuses the settings page's update logic, and the host appends the real outcome. Creating follow-ups stays withManageFollowUp.NotificationSettings: read, and update only the fields given (quiet hours, caps, digest slots, briefs, heartbeat, …). Also a temporary snooze (≤24 h,snoozeUntilin settings): everything except P0 decisions and immediate notices is held and digested when the snooze ends. It survives restarts and expires on its own; the settings page shows "静音到 HH:MM" with a cancel button.Authority
Not verified
Not tried in the real app.
🤖 Generated with Claude Code