Skip to content

fix(calendar): объединить напоминания одного события - #89

Open
yakovmakovets wants to merge 4 commits into
smixs:mainfrom
yakovmakovets:feat/google-calendar-event-policy
Open

fix(calendar): объединить напоминания одного события#89
yakovmakovets wants to merge 4 commits into
smixs:mainfrom
yakovmakovets:feat/google-calendar-event-policy

Conversation

@yakovmakovets

@yakovmakovets yakovmakovets commented Jul 29, 2026

Copy link
Copy Markdown

Проблема

Запрос «напомни за день, за час и за 10 минут» должен создавать одно событие нужной длительности с
несколькими напоминаниями, а не несколько коротких событий.

Изменение

В существующий навык google-workspace добавлены компактные правила работы с событиями Google
Calendar:

  • одной встрече, поездке или временному интервалу соответствует один объект события;
  • несколько оповещений передаются полным массивом reminders.overrides с
    reminders.useDefault: false;
  • поддерживаются до пяти уникальных сочетаний popup/email и интервала;
  • для recurring-события перед изменением или удалением уточняется экземпляр или вся серия;
  • для all-day события end.date указывает день после последнего дня;
  • добавлен пример gws calendar events insert с тремя напоминаниями.

OAuth-flow, gws, instructions.md, Telegram-канал и остальные навыки не изменяются.

Документация

Summary by CodeRabbit

  • Documentation
    • Updated Google Calendar guidance with clearer rules for creating events and configuring reminders.
    • Improved examples and instructions for recurring and all-day events.
    • Replaced the previous command example with a more complete event insertion example, including explicit reminder overrides.

@yakovmakovets

Copy link
Copy Markdown
Author

Отдельно отмечу архитектурное решение: сценарии разделены на create, reschedule, update и delete, потому что Eve сначала видит только короткие descriptions и загружает полный текст выбранного навыка по необходимости. Так создание события получает подробные правила профиля и напоминаний, а перенос, правка и удаление сохраняют компактный контекст. Буду признателен за замечания по формату Calendar defaults в CORE и границам каждого сценария.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: de310bb6-e094-4e71-975b-55bb6e547204

📥 Commits

Reviewing files that changed from the base of the PR and between 715497f and 9da93c8.

📒 Files selected for processing (1)
  • agent/skills/google-workspace.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • agent/skills/google-workspace.md

📝 Walkthrough

Walkthrough

Обновлены инструкции Google Calendar: удалён прежний CLI-пример, добавлены правила формирования объектов событий, повторяющихся и событий на весь день, а также настройки напоминаний через reminders.useDefault и reminders.overrides.

Changes

Руководство по событиям Google Calendar

Layer / File(s) Summary
Правила формирования объекта события
agent/skills/google-workspace.md
Описаны структура событий, повторяющиеся и события на весь день, настройка напоминаний и команда gws calendar events insert с start, end и reminders.overrides.

Estimated code review effort: 1 (Trivial) | ~2 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the reminder-handling focus of the change and is concise and specific.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (4)
scripts/google-calendar-skill.test.mjs (3)

14-23: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the changed root routing contract.

This test only loads google-workspace.md; regressions in agent/instructions.md lines 29-31 would remain green. Load that file and assert the structured-JSON requirement, Calendar scenario-skill routing, and exit-code-2 onboarding requirement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/google-calendar-skill.test.mjs` around lines 14 - 23, Extend the test
around the existing Google Workspace routing assertions to also load
agent/instructions.md and verify its root routing contract: structured JSON
responses, Calendar requests routed to scenario skills, and exit-code-2
onboarding behavior. Keep the existing focused-skill checks unchanged.

64-70: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use Unicode-aware boundaries for the affirmative-language gate.

The separator whitelist excludes Markdown delimiters, quotes, and em dashes, so forms such as —не or «не can evade the check. It also flags без without understanding whether it is an instruction. Normalize punctuation or use Unicode letter/non-letter boundaries and add representative fixtures.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/google-calendar-skill.test.mjs` around lines 64 - 70, Update the
negativeInstruction check in the “focused Calendar skills use affirmative
instructions” test to use Unicode-aware letter/non-letter boundaries rather than
the narrow separator whitelist, so forms such as —не and «не are detected
without incorrectly matching inside words. Add representative fixtures covering
Markdown delimiters, quotes, em dashes, and the existing negative terms, while
preserving the current skill coverage.

25-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert safety sequencing, not just keyword presence.

These checks would pass even if the live insert occurs before confirmation, sendUpdates is placed in the event body, pagination is omitted, or sensitive values are echoed. Add order-sensitive assertions for dry-run → confirmation → live write, plus explicit checks for parameter placement and redaction wording.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/google-calendar-skill.test.mjs` around lines 25 - 45, Strengthen the
Google Calendar policy tests around the create policy content by asserting the
required sequence of dry-run, explicit confirmation, and live insert; verify
sendUpdates is passed as an API parameter rather than included in the event
body; require pagination handling; and assert wording that sensitive values are
redacted rather than echoed. Use order-sensitive matching for the workflow and
targeted assertions for parameter placement and redaction.
agent/skills/google-calendar-create.md (1)

48-53: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Disambiguate Google Calendar defaults from the saved CORE profile.

Line 50 says to ignore “calendar defaults”, while line 52 says to use Calendar defaults. Explicitly name the former as Google Calendar defaultReminders and state that only those API defaults are ignored; otherwise the persisted CORE profile may be skipped. The API distinguishes calendar defaults from per-event reminder overrides. (developers.google.com)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent/skills/google-calendar-create.md` around lines 48 - 53, Clarify the
reminders guidance by identifying “calendar defaults” as Google Calendar API
defaultReminders and stating that only those defaults must be ignored. Ensure
the workflow still uses the persisted CORE profile when available, then the
current request’s reminders, and only falls back to Calendar defaults when
neither source provides reminders.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@agent/skills/google-calendar-create.md`:
- Around line 78-81: Update the sensitive-data confirmation flow in the calendar
creation instructions to display only categories and redacted identifiers, never
the exact detected values. Preserve the warning about calendar participant and
reader access, request explicit confirmation, and store exact sensitive values
only after confirmation.
- Around line 67-74: Update the workflow around the dry-run and live `gws
calendar events insert` steps so the JSON request is dry-run first, followed by
the event summary and an explicit user confirmation gate. Execute the
non-dry-run insert only after confirmation; clarify that an explicit creation
request does not bypass this gate.
- Around line 45-46: Update the participant-handling instructions in the
calendar event creation guidance to require sendUpdates in --params alongside
calendarId, using all, externalOnly, or none. Keep --json limited to the event
resource and do not place sendUpdates in the request body.
- Around line 62-65: Update the calendar conflict-checking flow in the
events-list step to retrieve every paginated result using --page-all with NDJSON
handling, or an equivalent pageToken loop. Run the existing time-and-meaning
duplicate detection against the complete event set before offering an update or
creating a new event.

In `@agent/skills/google-calendar-delete.md`:
- Around line 10-13: Преобразуйте выбранную область recurring-события в явный
API-target перед каждой mutable-операцией: в
agent/skills/google-calendar-delete.md (строки 10-13) укажите для series
recurringEventId, а для instance eventId и originalStartTime; в
agent/skills/google-calendar-reschedule.md (строки 11-17) добавьте те же targets
для patch и eventId плюс originalStartTime для move; в
agent/skills/google-calendar-update.md (строки 9-10) укажите parent
recurringEventId для patch серии и eventId с originalStartTime для экземпляра.
- Around line 11-16: Добавь явный выбор режима sendUpdates для операций delete,
patch и move: в google-calendar-delete.md запроси режим для удаления, отобрази
его в dry-run и подтверждении и передай в API; в google-calendar-reschedule.md
сделай то же для patch и move. Убедись, что выбранный режим явно показывается
пользователю и используется при выполнении соответствующего запроса.
- Around line 14-16: Закройте TOCTOU во всех mutation skills: в
agent/skills/google-calendar-delete.md (строки 14-16),
agent/skills/google-calendar-reschedule.md (строки 22-24) и
agent/skills/google-calendar-update.md (строки 24-26) замените шаги 7-10 так,
чтобы после подтверждения заново получать etag и передавать If-Match:<etag> в
delete/patch, а перед move выполнять отдельную проверку etag. При конфликте не
выполнять операцию и запрашивать новое подтверждение.

In `@agent/skills/google-calendar-reschedule.md`:
- Around line 32-33: Уточни описание в разделе о переносе событий: в тексте про
сохранение исходных полей явно укажи, что напоминания сохраняются, кроме случая
применения профиля `Calendar defaults` через `useDefault:true`. Согласуй
формулировку со строками 19–20, не изменяя поведение остальных полей.
- Around line 18-24: Дополните инструкцию для сценария useDefault:true явной
остановкой после первой ошибки patch или move: повторно получите событие, точно
сообщите выполненные и невыполненные шаги, затем предложите компенсационное
действие или ручное продолжение вместо безусловного повтора. Сохраните move как
отдельный API-запрос без тела patch и опишите обработку частичных результатов
после каждого шага.

In `@agent/skills/google-calendar-update.md`:
- Around line 18-20: Обнови инструкцию вокруг проверки чувствительных сведений в
сценарии обновления календаря: до финального подтверждения, dry-run и успешной
проверки etag не записывай их в календарь, а сохраняй только в подготовленном
patch. Выполняй запись в указанное пользователем поле лишь после финального
подтверждения и успешной условной мутации.

---

Nitpick comments:
In `@agent/skills/google-calendar-create.md`:
- Around line 48-53: Clarify the reminders guidance by identifying “calendar
defaults” as Google Calendar API defaultReminders and stating that only those
defaults must be ignored. Ensure the workflow still uses the persisted CORE
profile when available, then the current request’s reminders, and only falls
back to Calendar defaults when neither source provides reminders.

In `@scripts/google-calendar-skill.test.mjs`:
- Around line 14-23: Extend the test around the existing Google Workspace
routing assertions to also load agent/instructions.md and verify its root
routing contract: structured JSON responses, Calendar requests routed to
scenario skills, and exit-code-2 onboarding behavior. Keep the existing
focused-skill checks unchanged.
- Around line 64-70: Update the negativeInstruction check in the “focused
Calendar skills use affirmative instructions” test to use Unicode-aware
letter/non-letter boundaries rather than the narrow separator whitelist, so
forms such as —не and «не are detected without incorrectly matching inside
words. Add representative fixtures covering Markdown delimiters, quotes, em
dashes, and the existing negative terms, while preserving the current skill
coverage.
- Around line 25-45: Strengthen the Google Calendar policy tests around the
create policy content by asserting the required sequence of dry-run, explicit
confirmation, and live insert; verify sendUpdates is passed as an API parameter
rather than included in the event body; require pagination handling; and assert
wording that sensitive values are redacted rather than echoed. Use
order-sensitive matching for the workflow and targeted assertions for parameter
placement and redaction.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 35b3e650-224b-45b6-9deb-fe7a56998826

📥 Commits

Reviewing files that changed from the base of the PR and between a0cdec7 and c6319a6.

📒 Files selected for processing (7)
  • agent/instructions.md
  • agent/skills/google-calendar-create.md
  • agent/skills/google-calendar-delete.md
  • agent/skills/google-calendar-reschedule.md
  • agent/skills/google-calendar-update.md
  • agent/skills/google-workspace.md
  • scripts/google-calendar-skill.test.mjs

Comment thread agent/skills/google-calendar-create.md Outdated
Comment thread agent/skills/google-calendar-create.md Outdated
Comment thread agent/skills/google-calendar-create.md Outdated
Comment thread agent/skills/google-calendar-create.md Outdated
Comment thread agent/skills/google-calendar-delete.md Outdated
Comment thread agent/skills/google-calendar-delete.md Outdated
Comment thread agent/skills/google-calendar-delete.md Outdated
Comment thread agent/skills/google-calendar-reschedule.md Outdated
Comment thread agent/skills/google-calendar-reschedule.md Outdated
Comment thread agent/skills/google-calendar-update.md Outdated
@yakovmakovets

Copy link
Copy Markdown
Author

Обновил PR по замечаниям CodeRabbit в коммите 34c3ea7.

Исправлено:

  • sendUpdates передаётся через --params для insert, patch, move и delete и показывается пользователю;
  • создание всегда проходит dry-run, показ итогов и отдельное финальное подтверждение;
  • поиск обрабатывает все страницы до исчезновения nextPageToken;
  • чувствительные значения остаются маскированными в сообщениях подтверждения;
  • instance и series преобразуются в точный eventId;
  • двухшаговый patch + move останавливается на первой ошибке и сообщает частичный результат;
  • уточнено различие Google defaultReminders и профиля Calendar defaults;
  • усилены контрактные регрессионные тесты.

По If-Match оставил отдельное техническое объяснение в inline-треде: текущий gws не поддерживает произвольные HTTP-заголовки.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

@yakovmakovets, запускаю повторный review PR #89 с учётом обновлений в 34c3ea7 и пояснения по ограничению gws для If-Match.


✏️ Learnings added
Learnt from: yakovmakovets
URL: https://github.com/smixs/iva/pull/89

Timestamp: 2026-07-29T16:23:18.812Z
Learning: In the Google Calendar skills for this repository, the current `gws` CLI does not support passing arbitrary HTTP headers; therefore direct HTTP `If-Match` conditional requests cannot be used. Existing-event mutation workflows should instead re-fetch and compare the event `etag` before the final confirmed operation.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@yakovmakovets yakovmakovets changed the title feat(calendar): добавить навыки работы с событиями feat(calendar): корректно управлять событиями Google Calendar Jul 29, 2026
@yakovmakovets

Copy link
Copy Markdown
Author

Уточнил реализацию после замечания и сверки с актуальной документацией Eve.

В отдельном коммите 1d25ea6:

  • убрана ручная цепочка google-workspace → сценарный Calendar-навык;
  • Eve теперь выбирает create, reschedule, update или delete напрямую по description;
  • общий google-workspace оставлен для общих операций, чтения календаря и OAuth;
  • из общего навыка убраны пересекающиеся триггеры создания события и промежуточный маршрутизатор;
  • регрессионная проверка теперь фиксирует прямую маршрутизацию по описаниям навыков.

Также переписал заголовок и описание PR: сначала сформулирована пользовательская проблема и ожидаемое поведение, затем устройство решения и ссылки на документацию Eve и Google.

@smixs

smixs commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Спасибо за серьёзную проработку - два раунда правок по ревью, сверка с докой eve, продуманная маскировка чувствительных данных. Проблема, которую ты решаешь, реальная и фикс мы хотим: «напомни за день, за час и за 10 минут» действительно должно быть одним событием с тремя reminders.overrides, а не тремя событиями.

Но в текущем объёме PR не возьмём - он решает 15-строчную проблему 340 строками. Разбор по пунктам, чтобы было понятно, что именно смущает:

Объём и UX. С этими скиллами каждое «поставь встречу завтра в 15» проходит: анкету профиля из 6 вопросов → чтение схемы API → выгрузку всех страниц событий → поиск дублей → dry-run → показ итогов → явное подтверждение → insert. Для личного ассистента это слишком церемонно: простая просьба должна исполняться одним шагом.

Дубли. Блок «серия vs экземпляр» повторён дословно в 3 скиллах, правила слияния напоминаний - в 3, etag-перепроверка - в 3, допрос про sendUpdates - в 4. Мы понимаем, что это цена самодостаточности eve-скиллов, но именно поэтому нарезка на 4 файла здесь не окупается - при первой правке копии разъедутся.

Calendar defaults в CORE.md. CORE ограничен ~1200 символами и едет в каждый промпт, включая некалендарные - хранить там настройки календаря нельзя. Таймзону gws и так берёт из Google-аккаунта, остальное берётся из запроса.

etag. Как выяснилось в треде, gws не поддерживает If-Match - «перепроверка etag» в трёх скиллах остаётся ручной и ничего не гарантирует (TOCTOU никуда не девается). Лучше вообще без неё.

Тест. Греп русской прозы завязывает CI на формулировки: любая редакция текста скилла уронит сборку. А запрет слов «не/ни/без/никогда» конфликтует со стилем самого репо (instructions.md пишет «НИКОГДА» капсом). Инструкции-скиллы мы тестами прозы не покрываем.

instructions.md. Замена «ОБЯЗАТЕЛЬНО сначала загрузи скилл google-workspace» на «загрузи при коде 2» меняет поведение для всех Google-сервисов, не только календаря - это отдельная тема, в этом PR верни как было.

Что предлагаем оставить - урезать PR до ~15-20 строк в существующем agent/skills/google-workspace.md, без новых файлов:

  1. Правило «одно событие»: одной встрече/поездке/интервалу соответствует один объект события; несколько оповещений - это reminders.overrides одного события.
  2. reminders.useDefault: false + полный массив overrides; до 5 штук; методы popup/email; убирать одинаковые пары method+minutes.
  3. Твой пример gws calendar events insert с overrides (сократив).
  4. Однострочное правило для повторяющихся событий: перед изменением/удалением уточнить у пользователя, экземпляр или вся серия.
  5. All-day: end.date - следующий день после последнего дня.

Description google-workspace.md можешь сжать, как у тебя, но триггеры «создай встречу» оставь - календарная запись остаётся в этом скилле.

Урежешь до этого объёма - смержим быстро. Если некогда, скажи - сделаем компактный вариант сами с кредитом тебе в CHANGELOG.

@yakovmakovets yakovmakovets changed the title feat(calendar): корректно управлять событиями Google Calendar fix(calendar): объединить напоминания одного события Jul 30, 2026
@yakovmakovets

Copy link
Copy Markdown
Author

Спасибо за подробный разбор — согласен с границей задачи.

В коммите 715497f PR сокращён до одного изменения в agent/skills/google-workspace.md:

  • удалены четыре сценарных навыка, Calendar defaults в CORE, dry-run/etag/sendUpdates-процедуры и тесты формулировок;
  • instructions.md возвращён к исходному поведению;
  • сохранён один объект на реальный временной интервал, полный reminders.overrides, лимит и дедупликация напоминаний, правило recurring/all-day и короткий пример gws calendar events insert.

Финальный diff: один файл, +20 / −1. Спасибо за предложение более точной и практичной формы.

@yakovmakovets
yakovmakovets force-pushed the feat/google-calendar-event-policy branch from 715497f to 9da93c8 Compare July 30, 2026 05:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants