fischer-agentkit/docs/brainstorms/2026-06-23-calendar-schedul...

197 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
date: 2026-06-23
topic: calendar-schedule
---
## Summary
在 AgentKit 客户端右侧面板嵌入行事历可展开为大抽屉通过混合模式ReAct 工具调用 + 时间关键词触发的后处理提取)自动捕获对话中的日程,同时支持完整的手动管理——循环事件、自定义类型、标签、三种视图(日历/卡片/列表UI 对标 Notion Calendar。日程双向同步 Apple Calendar (CalDAV)、Outlook (Graph API) 和 iCal/ICS配套独立的多渠道提醒子系统客户端 + 邮件 + Webhook个人为主 + 共享邀请。
## Problem Frame
Agent 对话中频繁产生可执行的时间安排——会议时间、截止日期、跟进任务——但这些信息当前无处记录。用户必须手动将这些内容转移到外部日历中,这个过程容易遗漏,尤其在长对话中多个时间点被讨论时。痛点不在"缺少一个日历应用",而在"Agent 产生的日程与日历之间没有桥梁":对话结束后,时间承诺就消失了。
## Key Decisions
**混合 Agent 识别模式。** ReAct 工具调用捕获实时意图Agent 在对话中主动调用 `create_event`),后处理提取作为兜底——但仅在对话包含时间关键词时触发 LLM 提取,避免每轮对话都产生额外 LLM 调用。两层机制互补:工具调用覆盖 Agent 已识别的明确日程,后处理覆盖 Agent 未主动识别但对话中隐含的时间安排。
**右侧面板 + 大抽屉而非独立页面。** 日历紧贴对话上下文,用户不用切换页面就能看到即将到来的日程。需要全屏管理时展开为大抽屉。这牺牲了独立页面的全屏日历体验,但换来了日程与对话的紧密耦合——这是核心痛点的解法。
**提醒系统作为独立子系统。** 多渠道提醒(客户端推送 + 邮件 + Webhook需要后台调度器、通知规则、渠道适配器、投递追踪——这不仅是日历的一个功能而是 AgentKit 目前不存在的全新基础设施。作为独立子系统设计,未来可被其他功能复用。
**个人日历 + 共享邀请,不做团队日历。** 用户有自己的私人日历,可以邀请其他用户参加事件(类似 Google Calendar 的邀请),但不支持多用户共同编辑同一日历。团队日历是不同的产品形态,不在此次范围内。
## Actors
- A1. **终端用户** — 管理个人日历,手动创建/查看/编辑/删除事件,管理事件类型和标签,配置提醒规则
- A2. **Agent** — 在 ReAct 循环中自主识别日程意图并调用日历工具创建事件;后处理提取层在时间关键词触发时分析对话内容
- A3. **外部日历服务** — Apple Calendar (CalDAV)、Outlook (Microsoft Graph API)、iCal/ICS 通用格式,作为双向同步目标
- A4. **提醒子系统** — 后台调度器定期扫描即将到期的事件,根据提醒规则通过配置的渠道分发通知
## Requirements
### 事件数据模型
- R1. 事件包含标题、描述、开始时间、结束时间、全天标记、地点字段
- R2. 事件支持循环模式:每日、每周、每月、自定义 RRULE 规则(至少支持 INTERVAL、COUNT、UNTIL、BYDAY
- R3. 事件支持自定义事件类型——用户可创建带名称和颜色的分类(如"会议"蓝色、"截止"红色),事件创建时选择类型
- R4. 事件支持多标签——用户可自定义标签,单个事件可挂多个标签,支持按标签筛选
- R5. 事件支持时间段——开始时间 + 结束时间,不限于时间点;全天事件和跨天事件均支持
### 视图模式
- R6. 日历视图——月/周/日网格布局,支持拖拽创建(拖选时间段直接建事件)、拖拽移动(拖动事件改变时间)
- R7. 卡片视图——看板风格,按日期或事件类型分组,卡片可拖拽调整分组
- R8. 列表视图——按时间排序的列表,支持行内编辑和批量操作
- R9. 三种视图在右侧面板和大抽屉中均可切换使用
### Agent 自动识别
- R10. Agent 在 ReAct 循环中可调用日历工具集:`create_event`、`query_events`、`update_event`、`delete_event`
- R11. 后处理提取在对话轮次结束后运行但仅当对话内容包含时间关键词时触发——关键词列表包括但不限于明天、下周、今天下午、X点、X月X日、开会、截止、deadline、schedule、reminder、提醒、预约
- R12. 时间关键词检测使用正则/关键词匹配(零 LLM 调用),命中后才发起 LLM 提取请求
- R13. Agent 创建的事件标记 `source="agent"`,并关联到 originating 对话 ID可在日历中追溯来源
- R14. 后处理提取创建的事件标记 `source="post_extract"`,同样关联对话 ID
- R15. 用户可在 UI 中区分手动创建、Agent 创建、后处理提取的事件(通过来源标记或颜色区分)
### 手动管理
- R16. 用户可通过 UI 手动创建、编辑、删除事件——三种视图均支持创建入口
- R17. 日历视图支持拖拽改期——拖动事件到新时间位置即可调整开始/结束时间
- R18. 事件类型和标签可在事件编辑界面中设置和修改
- R19. 支持批量操作:多选事件后批量删除、批量修改类型/标签
### 外部日历同步
- R20. 与 Apple Calendar 通过 CalDAV 协议双向同步——在 AgentKit 创建/修改/删除的事件同步到 Apple Calendar反之亦然
- R21. 与 Outlook Calendar 通过 Microsoft Graph API 双向同步——同上双向
- R22. 支持 iCal/ICS 格式的导入和导出——可从 .ics 文件导入事件,可将日历导出为 .ics
- R23. 同步冲突采用 last-write-wins 策略,冲突时保留最后修改的版本,并向用户发送冲突通知
- R24. 用户可在设置中配置每个外部日历的同步频率和同步范围(哪些事件类型参与同步)
### 提醒子系统
- R25. 事件支持提醒规则——可配置多个提醒(如"提前15分钟"、"提前1天"),每个提醒指定渠道
- R26. 提醒渠道支持客户端内通知WebSocket 推送 / Tauri 系统通知、邮件、Webhook
- R27. 后台调度器定期扫描即将到期的事件,匹配提醒规则,通过配置的渠道分发通知
- R28. 用户可为每种事件类型配置默认提醒规则——新建事件时自动继承
- R29. 提醒投递状态可追踪(已发送/已读/失败),失败的提醒有重试机制
### 共享与邀请
- R30. 用户可邀请其他用户参加事件——通过用户名或邮箱搜索并邀请
- R31. 被邀请用户收到通知,可接受/拒绝/暂定
- R32. 事件创建者可查看邀请回复状态(谁接受、谁拒绝、谁未回复)
- R33. 被邀请用户的事件在其日历中以特殊样式标记(如半透明或边框区分)
### UI/UX
- R34. 日历嵌入右侧面板作为标签页(与 Workflow/Monitor 并列),展示今日/近期日程摘要
- R35. 右侧面板日历可展开为大抽屉——覆盖大部分屏幕,提供完整的三视图管理体验
- R36. UI 遵循 Notion Calendar 设计语言——简洁排版、充足留白、流畅拖拽、柔和配色
- R37. Agent 创建事件时,右侧面板实时更新(无需手动刷新),并有视觉提示(如高亮动画)
## Key Flows
- F1. Agent 工具调用创建日程
- **Trigger:** Agent 在 ReAct 循环中识别到对话内容包含明确的时间安排
- **Actors:** A2 (Agent), A1 (用户)
- **Steps:** Agent 调用 `create_event` 工具,传入标题/时间/类型等参数 → 工具执行写入 → 返回创建结果 → Agent 在回复中告知用户已创建日程 → 右侧面板实时更新显示新事件
- **Outcome:** 事件被创建并标记 `source="agent"`,用户在对话中收到确认
- **Covers:** R10, R13, R37
- F2. 后处理提取创建日程
- **Trigger:** 对话轮次结束,对话内容命中时间关键词正则
- **Actors:** A2 (Agent 后处理层), A1 (用户)
- **Steps:** 关键词检测命中 → 发起 LLM 提取请求,分析对话中的时间安排 → LLM 返回提取结果0 或多个事件) → 写入日历,标记 `source="post_extract"` → 在对话中插入轻量提示"检测到 N 条日程,已添加到日历"
- **Outcome:** 隐含的日程被捕获,用户收到提示可查看/修改
- **Covers:** R11, R12, R14
- F3. 外部日历双向同步
- **Trigger:** 定时同步任务触发,或用户手动触发同步
- **Actors:** A3 (外部日历服务), A1 (用户)
- **Steps:** 拉取外部日历变更 → 与本地事件比对 → 检测冲突 → last-write-wins 解决冲突 → 推送本地变更到外部日历 → 冲突时向用户发送通知
- **Outcome:** 本地与外部日历保持一致,冲突被记录和通知
- **Covers:** R20, R21, R23
- F4. 提醒分发
- **Trigger:** 后台调度器扫描到事件即将到达提醒时间点
- **Actors:** A4 (提醒子系统), A1 (用户)
- **Steps:** 调度器匹配提醒规则 → 按规则配置的渠道分发通知(客户端推送 / 邮件 / Webhook → 记录投递状态 → 失败时重试
- **Outcome:** 用户在事件前通过配置的渠道收到提醒
- **Covers:** R25, R26, R27, R29
- F5. 手动创建事件
- **Trigger:** 用户在任意视图中触发创建操作(点击新建、拖选时间段、列表中添加)
- **Actors:** A1 (用户)
- **Steps:** 打开事件编辑表单 → 填写标题/时间/类型/标签/提醒/地点 → 保存 → 事件出现在日历中 → 如配置了外部同步,异步推送到外部日历
- **Outcome:** 事件被创建并可管理
- **Covers:** R16, R18
## Acceptance Examples
- AE1. Agent 在对话中识别日程
- **Covers:** R10, R13, R15
- **Given:** 用户与 Agent 对话,用户说"下周三下午3点开个产品评审会"
- **When:** Agent 在 ReAct 循环中处理该输入
- **Then:** Agent 调用 `create_event` 创建事件(标题="产品评审会", 开始时间=下周三15:00, source="agent"),并在回复中告知"已为您创建下周三下午3点的产品评审会日程"
- AE2. 后处理提取被关键词门控
- **Covers:** R11, R12, R14
- **Given:** 用户与 Agent 对话,对话内容为"这个方案不错,我们继续优化吧"
- **When:** 对话轮次结束,后处理层检查时间关键词
- **Then:** 关键词检测未命中(无时间相关词),不发起 LLM 提取请求,不创建任何事件
- AE3. 后处理提取在关键词命中时运行
- **Covers:** R11, R12, R14
- **Given:** 用户与 Agent 对话,对话内容为"好的,那下周二之前把文档发给我"
- **When:** 对话轮次结束,后处理层检查时间关键词
- **Then:** 关键词"下周二"命中 → 发起 LLM 提取 → 创建事件(标题="发送文档", 截止时间=下周二, source="post_extract")→ 对话中插入提示"检测到 1 条日程,已添加到日历"
- AE4. 同步冲突解决
- **Covers:** R23
- **Given:** 用户在 AgentKit 修改了事件 A改到周三同时在 Outlook 也修改了事件 A改到周四同步时检测到冲突
- **When:** 同步任务运行
- **Then:** 保留最后修改的版本last-write-wins向用户发送冲突通知"事件 A 存在同步冲突,已保留最新修改"
- AE5. 提醒按渠道分发
- **Covers:** R25, R26, R27
- **Given:** 事件 B 配置了两个提醒提前30分钟客户端通知 + 提前1天邮件通知
- **When:** 调度器扫描到事件 B 的提前1天提醒时间点到达
- **Then:** 通过邮件渠道发送提醒 → 记录投递状态为"已发送" → 继续等待提前30分钟的客户端通知时间点
## Scope Boundaries
### Deferred for later
- Google Calendar 集成——用户未选择,可在后续版本按需添加
- 团队共享日历——多用户共同编辑同一日历,当前仅支持个人 + 邀请
- 日历分析报表——事件统计、时间分布分析等
- 资源预订——会议室、设备等资源预约
- 移动端独立 App——当前仅 Web/Tauri 客户端
### Outside this product's identity
- 替代专业日历应用——AgentKit 行事历的核心差异化是 Agent 自动识别,不是与 Google Calendar/Notion Calendar 全功能竞争
- 项目管理——行事历不承担任务跟踪、甘特图、依赖管理等项目管理职能
## Dependencies / Assumptions
- 复用现有认证系统(`src/agentkit/server/auth/models.py` 的 `UserModel`)作为用户身份基础
- 复用现有 WebSocket 基础设施实现客户端实时通知推送
- 新增依赖:后台调度器(如 APScheduler用于提醒子系统
- 新增依赖CalDAV 客户端库用于 Apple Calendar 同步
- 新增依赖Microsoft Graph SDK 或直接 HTTP 客户端用于 Outlook 同步
- 新增依赖邮件发送能力SMTP 或第三方服务)用于邮件提醒渠道
- 假设:用户已拥有 Apple Calendar / Outlook 账号并可提供 OAuth/CalDAV 凭据
- 假设AgentKit 服务端可持续运行后台调度器进程(提醒子系统依赖)
## Sources / Research
- 现有架构落位参考:路由注册在 `src/agentkit/server/app.py`(第 928-954 行),前端布局在 `src/agentkit/server/frontend/src/components/layout/AgentLayout.vue`(第 146-156 行定义象限标签)
- 前端 Pinia stores 位于 `src/agentkit/server/frontend/src/stores/`API 客户端位于 `src/agentkit/server/frontend/src/api/`
- 后端路由模块位于 `src/agentkit/server/routes/`27 个 .py 文件),工具注册在 `src/agentkit/tools/registry.py`
- 用户模型位于 `src/agentkit/server/auth/models.py`SQLAlchemy 2 + SQLite可复用 `Base` 创建日历模型
- 消息总线 `src/agentkit/bus/message.py``AgentMessage` 可用于提醒子系统的内部通信
- DocumentTool`src/agentkit/tools/document_tool.py`)可作为 Agent 工具集成的参考模式——工具注册、ReAct 循环调用、结果返回