---
name: wecomcli-calendar
description: 何时用:仅当用户明确指向企业微信日程/会议室预订/忙闲时使用;泛指记事、提醒、本地日程默认走本地工具,在线会议走 wecomcli-meeting。企微日程:预约/预订会议室/查看/更新/取消/查忙闲;仅说'开会/约个会'未明确日程还是在线会议时,先按本技能消歧流程追问,不可臆断直接创建。
metadata:
  requires:
    bins: ["wecom-cli"]
---

# 企业微信日程技能

> 执行任何 `wecom-cli` 命令前，必须先读取并完成 `wecomcli-shared` 技能的公共前置检查。

## 适用范围

### 适用

- 预约 / 创建日程（含纯线下面对面碰头，即不带在线会议链接的安排）
- 查看 / 浏览日程（今天有什么安排、查本周日程）
- 搜索日程（按关键词、按组织人、按参与人找某个日程）
- 更新 / 修改日程（改时间、改地点、加减人、换会议室；不支持更新周期日程）
- 取消日程（不支持取消周期日程）
- 查忙闲 / 约多人共同空闲时段
- 订会议室、查会议室空不空、查办公楼

### 不适用

- 创建、更新、取消周期 / 重复日程（每周 / 每月 / 每天重复）→ 均不支持，引导用户在企业微信客户端手动操作
- 回复 / 拒绝日程邀请（接受 / 拒绝 / 待定，含"拒绝这个日程""不参加"）→ 不支持，引导用户在企业微信客户端操作或私信发起人

### 易混淆场景路由

- 用户要**创建含在线会议链接的会议**（需会议号 / 入会链接 / 远程或视频参会）→ 改用 `wecomcli-meeting`（创建会议会同时生成日程，无需在本技能再建）
- 用户仅说"开会 / 约个会 / 安排个会 / xx 会"等、**未明确是日程还是在线会议**（创建场景）→ 必须先用文字追问消歧（固定问题"需要创建日程还是会议？"，请用户回复"日程 / 会议"），不得臆断直接创建
- 用户要的会**同时支持线下与远程参会**（如"线下开、外地同事远程接入"）→ 含在线会议链接，改用 `wecomcli-meeting`
- **仅给了地点 / 会议室号**（如"在 1605 开会""订个会议室开会"）→ 不构成"明确是日程"，仍需先用文字询问消歧，不能因带地点就跳过追问
- **查询场景的模糊表述**（"最近有什么会 / 有哪些会"）→ 严禁追问，日程和会议都查并合并展示；仅当明确提到"在线会议 / 视频会议 / 入会链接 / 会议号 / 腾讯会议 / 远程参会"时才改用 `wecomcli-meeting` 只查会议

## 路由规则

| 用户意图 | 参考文档 |
|---------|---------|
| 预约日程、安排纯线下面对面会议（不含在线会议链接）、创建日程 | [calendar-create](references/calendar-create.md) |
| 看日程、今天有什么安排、查本周日程 | [calendar-agenda](references/calendar-agenda.md) |
| 找某个日程、项目评审是什么时候 | [calendar-search](references/calendar-search.md) |
| 查日程详情、看周期规则、看会议链接 | [calendar-agenda](references/calendar-agenda.md) |
| 取消日程、不开了 | [calendar-cancel](references/calendar-cancel.md) |
| 修改日程、更新日程、改时间、加人/移除人、换会议室 | [calendar-update](references/calendar-update.md) |
| 查忙闲、某人什么时候有空、约多人共同空闲 | [calendar-freebusy](references/calendar-freebusy.md) |
| 订会议室、查会议室空不空、查办公楼、约会议室 | [calendar-meeting-room](references/calendar-meeting-room.md) |

> **浏览 vs 搜索的选择原则**：用户提到**日程主题关键词**时走搜索；**只给了时间/日期而无日程主题关键词时，必须走列表浏览（`list`）**。需要周期规则、会议链接等详情时再读取单条日程详情补充。

## 技能边界：日程 vs 会议 [CRITICAL]

本技能（wecomcli-calendar）只负责**日程**——即非会议的日程安排，以及不含在线会议链接的纯线下面对面会议。**只要涉及在线会议链接（含远程/视频参会）的会议，一律归 wecomcli-meeting 技能**，不在本技能创建。

| 用户意图 | 归属技能 |
|---------|---------|
| 预约日程、安排纯线下面对面会议（不含在线会议链接）、订会议室、查/改/取消日程、查忙闲 | **本技能 wecomcli-calendar** |
| 创建含在线会议链接的会议、需要会议号或入会链接的会、需要远程/视频参会的会 | **wecomcli-meeting 技能** |

**消歧规则（仅创建场景）**：用户仅说"会议/会/开个会/约个会/安排个会/xx会/xx会议"等而未明确是日程还是会议时，**必须先用文字追问**，再路由到对应技能，禁止默认直接创建日程。此文字消歧仅用于「创建」；查询场景严格禁止追问——明确指向在线会议时只查会议，明确是日程/安排时只查日程，模糊表述（"会 / xx会 / 最近有什么会"等）则日程和会议都查（见下文「查询消歧」）。

> **问题与选项固定 [CRITICAL]**：消歧确认时，问题与可选项都必须原文照用、严格禁止修改任何内容——问题固定为 `"需要创建日程还是会议？"`，可选项固定为 `日程` / `会议`；不得改写问题措辞、增减或改写选项、翻译，或自行设计其他表述（如"在线会议 / 线上会议 / 视频会议 / 线下会议"等）。

用文字向用户提问：`需要创建日程还是会议？（请回复：日程 / 会议）`

- **"会议""会""开会"等词本身不构成"明确" [CRITICAL]**：这些词只表示要碰头议事，并未说明是日程还是会议。禁止仅因 query 里出现"会议"二字就默认归本技能（日程）创建，也禁止反向默认成会议——只要未明确，一律先用文字追问后再路由。只有出现"碰个面/创建日程"等纯线下信号时才直接留在本技能。
- 用户答「日程」→ 留在本技能，按"预约日程工作流"创建日程。
- 用户答「会议」→ 改用 `读取 wecomcli-meeting 技能` 创建会议（创建会议会同时生成对应日程，无需在本技能再建一条）。
- 用户已明确（如"碰个面""创建日程"=日程；"发个入会链接""要会议号""远程参会"=会议）时，直接路由，无需追问。
- **同时支持线下与远程参会**（如"线下开、外地同事远程接入"）时，因含在线会议链接，归 wecomcli-meeting 技能：创建会议即同时生成日程，无需在本技能另建日程。
- **仅有地点/会议室号**（如"在 1605 开会""到 A 座会议室碰一下""订个会议室开会"）不构成"明确是日程"——会议室里同样可能要远程接入，是日程还是会议仍未知，必须先用文字询问消歧，不能因为带了地点就跳过追问。

## 改约 / 重建日程前必须先识别会议关联 [CRITICAL]

"改约 / 改时间 / 挪到 / 顺延 / 重新约"等改期意图（即使用户说"取消……再约到……"，带"取消"也算改期），禁止机械拆成 `cancel` + `create`：

1. **先定位再判定会议关联**：`search` / `list` 返回均含 `meeting` 字段，定位到目标日程后**直接检查 `meeting.meeting_code`**——非空为「含在线会议链接的会议形态日程」，为空为纯日程；无需为此再补一次读取日程详情（仅当还需 `repeat_rule` 等字段时才补）。
2. **纯日程** → 用本技能路由表中更新日程意图改时间，禁止 cancel + create。
3. **含会议链接** → 改用 `读取 wecomcli-meeting 技能`，把 `meeting.meeting_id` 传入 `meeting update` 改时间（保留会议链接与参会人），无需重新 search 定位。

> **根因**：`create` 只能建纯日程、重建不出会议链接（能拆不能合），cancel + create 会让会议链接永久丢失，故改约一律走 update。


## 核心场景

### 1. 预约日程

读取 [calendar-create](references/calendar-create.md)，按其中"预约日程工作流"执行（信息补全 → 参与人解析 → 时间协商/忙闲检查 → 执行创建 → 结果反馈）。

### 2. 查看/搜索日程

| 场景 | 参考文档 |
|------|---------|
| 泛泛查询（"今天有什么安排"） | [calendar-agenda](references/calendar-agenda.md) |
| 有关键词（"项目评审是什么时候"） | [calendar-search](references/calendar-search.md) |
| 需要详情（只拿到 `schedule_id` 时补齐字段） | [calendar-agenda](references/calendar-agenda.md) |

> **浏览 vs 搜索**：有**日程主题关键词** → 搜索（不追问时间）；**只给时间/日期而无主题关键词 → 列表浏览（`list`）**，禁止把日期当 `keywords` 喂给 `search`。列表浏览已返回 `repeat_rule`，无需额外读取单条详情判断是否周期日程。

> **查询消歧（模糊查询时日程 + 会议都查）[REQUIRED]**：查询场景严格禁止用文字追问"是日程还是会议"——日程/会议消歧追问仅用于创建，查询时一律按以下规则直接处理、不追问。**判定分两个独立维度，不要混为一谈**：
>
> **维度一：查哪一边（日程 / 会议 / 两边都查）**
> - **明确是在线会议** → 用户明确提到"在线会议 / 视频会议 / 入会链接 / 会议号 / 腾讯会议 / 远程参会"等在线会议专属特征时，改用 `读取 wecomcli-meeting 技能` 只查会议。
> - **明确是日程 / 安排** → 用户说的明显是日程类内容（如"日程 / 安排 / 我的安排 / 日历 / 今天有什么安排"，且不带在线会议特征）时，只查日程。
> - **模糊表述无法判定**（"会 / xx会 / xx会议 / 开会 / 最近有什么会 / 有哪些会 / 找下 xx会议"等，既可能是日程也可能是会议）→ **日程和会议都要查**：既查日程，又 `读取 wecomcli-meeting 技能` 查会议。
>
> **维度二：每一边用 `search` 还是 `list`（与维度一独立，逐边各自判断）**
> - **有主题/名称关键词**（如"找下 xx会议""项目评审是什么时候"）→ 该边用 `search`（把关键词传入 `keywords`）。
> - **只有时间/日期或泛浏览无关键词**（如"最近有什么会""今天有什么安排"）→ 该边用 `list`，禁止把日期当`keywords` 喂给 `search`。
> - 即使"两边都查"，也按本维度对每一边各自选择：带关键词时两边都用 `search`，纯时间/泛浏览时两边都用 `list`。
>
> **合并展示**：两边都查时，合并结果后统一展示——按是否含在线会议链接分成「（会议）」（来自会议侧、或日程中 `meeting.meeting_code` 非空者）和「（日程）」（`meeting_code` 为空的纯日程）两部分，同一场会议在两边都出现时按"主题 + 时间"去重只保留一条，末尾汇总"共 N 场，其中会议 X 场、日程 Y 场"。
>
> - 本消歧仅针对查询；创建场景仍按上文"日程 vs 会议"用文字追问。

### 3. 取消日程

先定位日程（有**日程主题关键词**走搜索；只给时间/日期而无主题关键词走列表浏览 `list`，禁止把日期当 `keywords` 喂给 `search`），再判断是否周期日程（可直接读取列表返回的 `repeat_rule`，无需额外读取单条详情）——**周期日程不支持取消**，告知用户并引导其在企业微信客户端操作（见「已知限制」）。普通日程**不预先按"是否本人创建"拦截取消**，直接执行取消并根据工具返回结果判断能否取消（成功返回 `{}`，无权限则返回错误，此时告知用户并建议联系创建人）。**若用户意图实为"改约 / 挪到 / 顺延"（即使带"取消"字样），按上文「改约 / 重建日程前必须先识别会议关联」走更新流程。** 完整流程见 [calendar-cancel](references/calendar-cancel.md)。

### 4. 更新日程

- 先定位日程（有**日程主题关键词**走搜索；只给时间/日期而无主题关键词走列表浏览 `list`，禁止把日期当 `keywords` 喂给 `search`），判断是否周期日程——**周期日程不支持更新**，告知用户并引导其在企业微信客户端操作（见「已知限制」），禁止逐场 `update` 拼凑或改为取消重建。普通日程收集修改内容后执行更新，**不预先按"是否本人创建"拦截修改**，直接执行更新并根据工具返回结果判断能否修改（成功返回更新后的 `detail`，无权限则返回错误，此时告知用户并建议联系创建人）。
- **改时间/改地点/加减人/换会议室都走更新，不要取消重建。** 换会议室时须先经 `rooms search` 确认新会议室 `status=bookable` 再把新 `meeting_room_id` 传入更新（见 [calendar-meeting-room](references/calendar-meeting-room.md)）。
- **含在线会议链接的日程（定位结果中 `meeting` 非空）改时间不在本技能 update**，须改用 `读取 wecomcli-meeting 技能`（见上文「改约 / 重建日程前必须先识别会议关联」）。
- 更新日程的完整流程见 [calendar-update](references/calendar-update.md)。

### 5. 查询忙闲 / 共同空闲

查询参与人在指定时段的可用空闲时段（服务端已合并区间、过滤过去、按策略推荐），用于协调日程时间。详见 [calendar-freebusy](references/calendar-freebusy.md)。

## 核心概念

- **日程（Schedule）**：日程系统中的单个事件，含主题、起止时间、参与人等属性。
- **全天日程（All-day）**：`is_all_day=true`，只按日期占用，结束日期包含在日程内。
- **周期日程（Recurring）**：`repeat_rule.is_repeat=true`，按规则重复出现。
- **参与人（Attendee）**：以 `userid`（`wo` 前缀）标识。用户提供的是姓名时通过 `读取 wecomcli-contact 技能` 解析为 `userid`。
- **忙闲（FreeBusy）**：查询参与人在指定时段是否有日程占用。
- **地点（Location）**：日程的地点为一段自由文本（`location` 字段）。用户给的地点是**公司会议室**时，须经会议室查询（`rooms search`）预订、以 `meeting_room_id` 占用（见 [calendar-meeting-room](references/calendar-meeting-room.md)），不要把会议室名仅写进 `location`；用户给的是**非会议室的普通文本地点**时才直接写入 `location`。
- **会议室 / 办公楼（Meeting Room / Building）**：物理空间资源（与在线会议链接无关）。`buildings list` 查可访问办公楼，`rooms search` 查会议室可订性，创建日程时传 `meeting_room_id` 原子占用，更新日程时传 `meeting_room_id` 改订。详见 [calendar-meeting-room](references/calendar-meeting-room.md)。
- **时区（Timezone）**：每个日程带 `timezone`（`timezone_id` + `timezone_offset`）。日程的 `begin_time` / `end_time` 是该时区下的**墙上时间**，后台不做转换——传入和返回的时间字符串都按日程时区解释，禁止自行换算成东八区或本地时间。

## 核心规则


### 规则 1: userid 获取 [CRITICAL]

- `attendees` / `add_attendees` / `remove_attendees` / `userids` / `has_attendees` 等所有"成员 userid 列表"入参**统一为对象数组**，格式为 `[{"userid": "woxxx"}, {"userid": "woyyy"}]`，不接受姓名或平铺字符串数组。
- `organizer`（搜索按组织人）为单值，传 userid 字符串（`wo` 前缀），不是数组。
- 用户提供的是姓名时，通过 `读取 wecomcli-contact 技能` 解析为对应 userid；多候选人时列出供用户选择，不自行猜测。
- **禁止**把姓名当 userid 拼接，**禁止**凭记忆或猜测编造 userid。
- **原因**：日程 API 不支持用姓名匹配参与人，传入姓名会导致静默失败或邀请到错误的人。

### 规则 2: 写操作直接执行

- 创建日程、取消日程时，参数就绪后直接执行，无需向用户展示摘要或询问确认。
- 结果返回时**禁止暴露 userid**，只展示人名。
- **原因**：上层交互已完整展示操作内容并完成确认，此处再展示一遍会造成冗余。

### 规则 3: 用户交互必须用文字询问 [CRITICAL]

任何操作中，当必要参数不明确或需要用户做出选择时，**必须用文字直接向用户提问**，禁止自行猜测或使用默认值代替询问。提问时把可选项 / 候选值一并写进文字里，让用户直接回复。

以下情况均适用此规则：
- **必填参数及参与人缺失**：创建日程的必填参数（`subject` / `begin_time` / `end_time`）以及参与人 `attendees` 无法从上下文中推断时，必须用文字询问；其余非必填参数（如地点）用户未明确指定时不专门询问，直接走默认值
- **多候选项需用户选择**：搜索返回多个匹配日程、wecomcli-contact 技能搜索到多个同名候选人
- **操作范围需确认**：如更换会议室时查到多个 bookable 候选，需用户选定具体一个
- **冲突处理**：忙闲检查发现时间冲突，需用户决策

**文字询问的约束**：
- 列出的可选项 / 候选建议以 **2~4 个**为宜。可选候选多于 4 个时（如同名候选人、多个匹配日程），取最相关的前 4 个列出，并提示用户可进一步缩小范围（输入更精确的关键词 / 完整姓名 / 具体时间），不要一次性罗列 5 个及以上候选。
- **询问时间时，列出的候选时刻必须是精确到分钟的具体时刻**（如"明天 14:00"、"周六 10:30"），禁止给出"上午/下午/傍晚/午间/上班后/下班前"等模糊时间选项——模糊选项会导致用户回复后仍需二次追问具体几点，必须一次问到可直接落为 `begin_time` 的精确时刻。

### 规则 4: 任务简洁原则

只完成用户要求的操作，不额外添加其他操作。

### 规则 5: 输入合法性检查

执行写操作前，验证以下输入的合法性：
- **时间格式**：必须为 `YYYY-MM-DD HH:mm:ss`，拒绝模糊表述直接传参（如"明天"不能直接传入，需先解析为具体时间）
- **时间顺序**：`end_time` 必须晚于 `begin_time`，拒绝零时长或负时长日程
- **userid 格式**：必须为 `wo` 前缀的字符串，不接受纯数字或中文姓名
- **历史时间**：禁止创建完全在当前时刻之前的日程

### 规则 6: 输入安全处理

- 用户提供的是姓名时，必须经过 `读取 wecomcli-contact 技能` 搜索验证后才能转换为 userid。
- **禁止**把姓名直接拼接为 userid，**禁止**凭记忆或猜测编造。
- **原因**：用户输入的字符串可能不对应真实员工（姓名不唯一、已离职等），直接拼接会导致将日程邀请发送给错误的人，且此类错误无法被 API 在调用时拦截。

## 操作参考

| 操作参考 | 读取时机 | 说明 |
|----------|---------|------|
| [`calendar-agenda`](references/calendar-agenda.md) | 查看/获取日程详情时 | 查看日程安排（list + get） |
| [`calendar-create`](references/calendar-create.md) | 创建日程时 | 创建日程并邀请参与人 |
| [`calendar-search`](references/calendar-search.md) | 搜索日程时 | 按关键词搜索日程 |
| [`calendar-cancel`](references/calendar-cancel.md) | 取消日程时 | 取消日程（不支持周期日程） |
| [`calendar-update`](references/calendar-update.md) | 更新/修改日程时 | 更新日程信息（主题、时间、参与人、地点等） |
| [`calendar-freebusy`](references/calendar-freebusy.md) | 需要协调时间 / 查共同空闲时 | 查询共同空闲时段，协调日程时间 |
| [`calendar-meeting-room`](references/calendar-meeting-room.md) | 预订/更换会议室 / 查办公楼或会议室可订性时 | 办公楼清单（`buildings list`）+ 会议室可订性（`rooms search`），拿 `meeting_room_id` 供创建占用或更新改订 |

## 上下文传递表

> 此表描述接口间的数据流转契约，第一列"来源操作"为业务语义；各操作的完整参数与字段定义见对应 reference。

| 来源操作 | 从返回中提取 | 用于 |
|---------|-------------|------|
| 搜索（search） | `schedules[].schedule_id` | 单条详情、取消日程 |
| 列表浏览 / 单条详情（list / get） | `schedule_list[].schedule_id` | 单条详情、取消日程 |
| 搜索（search） | `schedules[].attendees[].name` | 直接展示参与人姓名，无需额外反查（搜索接口已返回） |
| 搜索（search） | `schedules[].creator_name` | 直接展示日程创建者姓名 |
| 搜索（search） | `next_cursor` + `has_more` | 分页翻页控制 |
| wecomcli-contact 技能搜索 | `userid`（`wo` 前缀） | 创建/更新日程的 `attendees` / `add_attendees` / `remove_attendees`、忙闲查询的 `userids`、搜索的 `has_attendees`（均组装为对象数组 `[{"userid": "woxxx"}]`）；搜索的 `organizer` 为单值 userid 字符串 |
| 搜索 / 列表浏览 / 单条详情 | `repeat_rule` | 判断是否周期日程（`is_repeat=true`）：命中时取消 / 更新均不支持，告知用户并引导企业微信客户端操作；`search`/`list` 均直接返回，无需补 `get` |
| 搜索 / 列表浏览 / 单条详情 | `meeting.meeting_code` | 识别该日程含在线会议链接（非空即「会议形态日程」，search/list/get 均直接返回，无需额外补 `get`）；改约 / 取消含会议链接日程时，直接把 `meeting.meeting_id` 传入 `wecomcli-meeting` 的 `meeting update` / `meeting cancel`，无需在 wecomcli-meeting 重新 search 定位 |
| 搜索 / 列表浏览 + 单条详情 | 搜索取 `schedules[].schedule_id`、列表/详情取 `schedule_list[].schedule_id` 与 `schedule_list[].repeat_rule` | 更新日程的定位与周期日程判断（命中周期日程则不支持更新） |
| 忙闲查询 | `slots[]`（含 `available_users`、`available_count`、`busy_users`） | 直接展示推荐时段，挑前几个让用户选择；展示时只用人名，userid 仅回传创建日程的 `attendees` |
| 会议室可订性查询（`rooms search`） | `target[].room.meeting_room_id` 或 `recommendations[].meeting_room_id` | 创建日程的 `meeting_room_id`（原子占用会议室）、更新日程的 `meeting_room_id`（改订会议室）；ID仅工具链流转，禁止展示，对用户只露会议室 name |

## 错误处理

> 原则：告诉用户**出了什么问题** + **可以怎么做** + **备选方案**。禁止静默失败。

| 场景 | 恢复建议 |
|------|---------|
| 搜索无结果 | 用文字提供恢复建议：1. 更换关键词重试；2. 按组织人搜索（提供姓名，解析 userid 后传 `organizer`）；3. 按参与人搜索（提供姓名，解析 userid 后传 `has_attendees`）；|
| 通讯录多候选人 | 用文字列出候选人（姓名+部门）供选择 |
| wecomcli-contact 技能搜索无结果 | 用文字提示用户确认姓名，等待重新输入 |
| 取消/修改非本人创建的日程 | 不预先拦截，直接执行命令；返回权限错误时说明当前用户无权操作，建议联系创建人 |
| 共同空闲查询返回空 `slots` | 引导用户扩大时间窗口或减少参与人，不要在同一窗口反复重试 |
| 共同空闲查询降级（`available_count < total_count`） | 告知哪些人冲突、几人能参加，由用户决定是否按降级时段安排或更换时间 |

## 输出质量标准

好的输出应满足以下条件：
- 日程列表：按开始时间升序排序，每条日程作为独立条目顺序输出（**禁止 markdown 表格**），每个条目只含主题、时间、参与人；超过 10 条只展示前 10 条
- 参与人展示：原样使用接口返回的 `attendees[].name` 字段（完全与接口返回的格式保持一致，如返回 `zhangsan(张三)` 就展示 `zhangsan(张三)`），不展示 userid
- 操作结果：明确告知成功/失败及原因，操作成功后展示日程摘要
- 错误提示：包含问题描述+恢复建议+备选方案，不暴露技术错误码

不可接受的输出：
- 直接展示 userid 而非姓名
- 遇到错误静默失败，不给用户任何提示
- 展示内部 schedule_id


## 输出格式规范

**参与人姓名格式 [REQUIRED]**：所有展示参与人的场景（创建反馈、单条摘要、列表等），姓名一律**原样使用接口返回的 `attendees[].name` 字段**，完全与接口返回的格式保持一致（如返回 `zhangsan(张三)` 就展示 `zhangsan(张三)`）；下文模板中的 `{人名}` 均指该原样 name。

**时间年份显示 [REQUIRED]**：下文"时间"行默认省略年份、只到月日（模板中的 `{月日}` 即指 `M月D日`）；仅当日程年份与当前年份不同（跨年）时，才在月日前补上年份，格式为 `{YYYY}年M月D日 {HH:mm}-{HH:mm}`。

**相对日期标签 [REQUIRED]**：当日程日期为昨天 / 今天 / 明天时，"时间"行在月日前加上相对词，格式 `{昨天|今天|明天} M月D日 {HH:mm}-{HH:mm}`（如 `时间：明天 6月11日 14:00-15:00`）；其余日期按 `{月日} {HH:mm}-{HH:mm}` 展示。

**创建成功反馈 [REQUIRED]**：创建日程成功后，输出内容只包含三部分：主题、时间、参与人，禁止输出其他任何内容和额外语句（不展示地点、提醒、schedule_id 等字段，也不附加说明、建议或寒暄）：
```
主题：{subject}
时间：{月日} {HH:mm}-{HH:mm}
参与人：{人名1}、{人名2}
```

**单条日程摘要**（用于查看/搜索单条场景，非创建反馈）：
```
主题：{subject}
时间：{月日} {HH:mm}-{HH:mm}
参与人：{人名1}、{人名2}
```

**日程列表展示规范 [REQUIRED]**（列表/搜索浏览均适用）：
- **禁止使用 markdown 表格**；每条日程作为独立条目顺序输出，按开始时间升序排序。
- 每个条目 **只展示三项：主题、时间、参与人**（不展示地点、提醒、schedule_id 等）。
- **超过 10 条时只展示前 10 条**，并在末尾告知"还有 N 条，需要查看更多吗？"。
- **会议 / 日程 分两部分展示**：判断依据是该日程是否带有会议链接——`meeting.meeting_code` 有值（非空）归为「会议」，为空 / 不存在归为「日程」（`search`/`list`/`get` 返回均含 `meeting` 字段，可直接判断）。**仅当本次结果中同时存在「会议」和「日程」两类时**，才把结果分成「（会议）」和「（日程）」两个部分分别展示：先列「（会议）」部分、再列「（日程）」部分；每部分内部按开始时间升序、逐条只展示主题/时间/参与人；末尾追加汇总"共 N 场，其中会议 X 场、日程 Y 场"。**当结果只有单一类别时**（全是会议或全是日程），不分部分、不加「（会议）」/「（日程）」标题，按普通列表直接展示。
- 分部分格式：
```
（会议）
1. {主题}
   时间：{月日} {HH:mm}-{HH:mm}
   参与人：{人名1}、{人名2}

（日程）
1. {主题}
   时间：{月日} {HH:mm}-{HH:mm}
   参与人：{人名1}、{人名2}
```

**时区标注 [REQUIRED]**：日程 `timezone_offset != 28800`（非东八区）时，展示时间必须带时区标注，格式 `{HH:mm}-{HH:mm}（{地区中文名} UTC±N）`，如 `14:00-15:00（纽约时间 UTC-5）`。
- `UTC±N` 由 `timezone_offset / 3600` 得出。
- 地区中文名由 `timezone_id` 推导（如 `America/New_York` → 纽约时间）；`timezone_id` 为空时省略中文名，只留 `（UTC-5）`。
- 东八区（`timezone_offset = 28800`，含 `Asia/Shanghai`、`Asia/Singapore` 等）不标注，保持现状。
- 适用于单条摘要的"时间"行、日程列表、创建/更新成功反馈；freebusy 的 `slots` 不适用（按本人时区展示）。

## 已知限制

| 限制 | 替代方案 |
|------|---------|
| **schedules list 查询窗口 ≤ 前后 30 天** | `begin_time`/`end_time` 必须落在「当前时刻前后 30 天」窗口内，超出范围服务端不返回。超出时直接告知用户超出可查范围、请重新给一个更短的时间范围，等用户重新提供后再调用 |
| **不支持创建/更新/取消周期（重复）日程** | 用户希望创建"每周/每月/每天重复"等周期日程，或对已识别为周期日程（`repeat_rule.is_repeat=true`）的日程发起更新、取消时，均直接告知用户目前不支持，并引导用户在企业微信客户端手动操作；禁止用创建多条单次日程、逐场 `update` 拼凑、`cancel`+`create` 重建、传入未公开参数等方式变通绕过 |
| **不支持回复 / 拒绝日程邀请（RSVP）** | 本技能不支持对收到的日程邀请做接受 / 拒绝 / 待定等回复（含"拒绝这个日程""不参加""婉拒邀请"等）。用户有此需求时，告知其本技能不支持，建议直接在企业微信客户端对该日程邀请操作，或通过消息告知日程发起人 |
| **共同空闲查询限制** | 周期日程仅查看最近两个月有修改的；单次查询窗口 ≤ 24h，超出需分批；`begin_time` 早于服务端当前时刻的部分会被自动截断，传纯历史窗口会返回空 `slots` |
