@rezti/dsh-rez-suite 0.1.49 → 0.1.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -2
- package/README.md +3 -3
- package/README.zh.md +2 -2
- package/cordis.patch.yml +1 -1
- package/lib/client.d.ts +31 -3
- package/lib/client.js +343 -7
- package/lib/index.js +244 -15
- package/lib/style.css +7 -0
- package/package.json +12 -11
- package/src/boss/mount.ts +4 -3
- package/src/boss/register.ts +1 -1
- package/src/boss/seed.ts +34 -0
- package/src/changelog.ts +48 -0
- package/src/channel-board.ts +55 -0
- package/src/client/locales.ts +62 -6
- package/src/client/panel/BoardTab.tsx +136 -0
- package/src/client/panel/ConfigTab.tsx +2 -2
- package/src/client/panel/StatusTab.tsx +31 -0
- package/src/client/panel/panel.module.css +7 -0
- package/src/client/settings-card.tsx +4 -1
- package/src/index.ts +3 -2
- package/src/protocol.ts +14 -0
- package/src/routes.ts +7 -1
- package/src/tools.ts +49 -6
- package/src/wecom-cli.ts +125 -0
- package/templates/boss/ops/AGENTS.md +2 -0
- package/templates/shared/wecom-cli.SOURCE.md +9 -0
- package/templates/shared/wecom-office/SKILL.md +32 -0
- package/templates/shared/wecomcli-calendar/SKILL.md +303 -0
- package/templates/shared/wecomcli-calendar/references/calendar-agenda.md +224 -0
- package/templates/shared/wecomcli-calendar/references/calendar-cancel.md +108 -0
- package/templates/shared/wecomcli-calendar/references/calendar-create.md +238 -0
- package/templates/shared/wecomcli-calendar/references/calendar-freebusy.md +207 -0
- package/templates/shared/wecomcli-calendar/references/calendar-meeting-room.md +170 -0
- package/templates/shared/wecomcli-calendar/references/calendar-search.md +206 -0
- package/templates/shared/wecomcli-calendar/references/calendar-update.md +272 -0
- package/templates/shared/wecomcli-contact/SKILL.md +58 -0
- package/templates/shared/wecomcli-disk/SKILL.md +389 -0
- package/templates/shared/wecomcli-doc/SKILL.md +137 -0
- package/templates/shared/wecomcli-doc/references/doc-contents-append.md +20 -0
- package/templates/shared/wecomcli-doc/references/doc-contents-overwrite.md +27 -0
- package/templates/shared/wecomcli-doc/references/doc-create.md +161 -0
- package/templates/shared/wecomcli-doc/scripts/build_docx.py +1375 -0
- package/templates/shared/wecomcli-doc-manage/SKILL.md +132 -0
- package/templates/shared/wecomcli-doc-manage/references/doc-members-update.md +24 -0
- package/templates/shared/wecomcli-doc-manage/references/doc-names-update.md +20 -0
- package/templates/shared/wecomcli-doc-manage/references/doc-rules-update.md +22 -0
- package/templates/shared/wecomcli-email/SKILL.md +218 -0
- package/templates/shared/wecomcli-email/references/forward-mail.md +131 -0
- package/templates/shared/wecomcli-email/references/get-mail.md +166 -0
- package/templates/shared/wecomcli-email/references/reply-mail.md +138 -0
- package/templates/shared/wecomcli-email/references/search-mail.md +111 -0
- package/templates/shared/wecomcli-email/references/security.md +53 -0
- package/templates/shared/wecomcli-email/references/send-mail.md +186 -0
- package/templates/shared/wecomcli-email/references/send-schedule.md +83 -0
- package/templates/shared/wecomcli-media/SKILL.md +98 -0
- package/templates/shared/wecomcli-meeting/SKILL.md +373 -0
- package/templates/shared/wecomcli-meeting/references/meeting-cancel.md +113 -0
- package/templates/shared/wecomcli-meeting/references/meeting-create.md +167 -0
- package/templates/shared/wecomcli-meeting/references/meeting-list.md +226 -0
- package/templates/shared/wecomcli-meeting/references/meeting-original-get.md +98 -0
- package/templates/shared/wecomcli-meeting/references/meeting-search.md +173 -0
- package/templates/shared/wecomcli-meeting/references/meeting-update.md +217 -0
- package/templates/shared/wecomcli-message/SKILL.md +200 -0
- package/templates/shared/wecomcli-shared/SKILL.md +73 -0
- package/templates/shared/wecomcli-sheet/SKILL.md +172 -0
- package/templates/shared/wecomcli-sheet/references/sheet-contents-update.md +47 -0
- package/templates/shared/wecomcli-sheet/references/sheet-ranges-get.md +45 -0
- package/templates/shared/wecomcli-sheet/references/sheet-rows-append.md +45 -0
- package/templates/shared/wecomcli-sheet/references/sheet-subsheets-add.md +26 -0
- package/templates/shared/wecomcli-sheet/references/sheet-subsheets-delete.md +20 -0
- package/templates/shared/wecomcli-smartpage/SKILL.md +170 -0
- package/templates/shared/wecomcli-smartpage/references/data-driven-pages.md +50 -0
- package/templates/shared/wecomcli-smartpage/references/formula/arraylist.md +369 -0
- package/templates/shared/wecomcli-smartpage/references/formula/datetime.md +283 -0
- package/templates/shared/wecomcli-smartpage/references/formula/logic.md +247 -0
- package/templates/shared/wecomcli-smartpage/references/formula/math.md +362 -0
- package/templates/shared/wecomcli-smartpage/references/formula/operators.md +246 -0
- package/templates/shared/wecomcli-smartpage/references/formula/pageblock.md +76 -0
- package/templates/shared/wecomcli-smartpage/references/formula/templates.md +410 -0
- package/templates/shared/wecomcli-smartpage/references/formula/text.md +377 -0
- package/templates/shared/wecomcli-smartpage/references/formula/user.md +22 -0
- package/templates/shared/wecomcli-smartpage/references/formula-reference.md +192 -0
- package/templates/shared/wecomcli-smartpage/references/mdx-syntax.md +739 -0
- package/templates/shared/wecomcli-smartpage/references/smartpage-edit.md +506 -0
- package/templates/shared/wecomcli-smartsheet/SKILL.md +154 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/README.md +53 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/ai_efficiency.md +709 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/connect_to_app.md +380 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/financial_accounting.md +369 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/hr_and_administration.md +475 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/ledger_records.md +156 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/manufacturing.md +395 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/marketing.md +186 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/office_essentials.md +299 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/personal_efficiency.md +70 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/procurement_logistics.md +325 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/project_management.md +564 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/rd_process_customer.md +222 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/rd_process_ops.md +105 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/rd_process_project.md +109 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/rd_process_research.md +92 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/sales_and_operations.md +446 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/store_management.md +431 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/team_tasks.md +274 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/wechat_customer.md +384 -0
- package/templates/shared/wecomcli-smartsheet/assets/templates/work_report.md +100 -0
- package/templates/shared/wecomcli-smartsheet/references/common.md +143 -0
- package/templates/shared/wecomcli-smartsheet/references/smart-sheet-chart-types.md +95 -0
- package/templates/shared/wecomcli-smartsheet/references/smart-sheet-edit.md +589 -0
- package/templates/shared/wecomcli-smartsheet/references/smart-sheet-field-types.md +438 -0
- package/templates/shared/wecomcli-smartsheet/references/smart-sheet-formula.md +845 -0
- package/templates/shared/wecomcli-smartsheet/references/smart-sheet-read.md +391 -0
- package/templates/shared/wecomcli-smartsheet/references/smart-sheet-record-values.md +201 -0
- package/templates/shared/wecomcli-smartsheet/references/smart-sheet-view-types.md +356 -0
- package/templates/shared/wecomcli-smartsheet/references/smart-sheet-webhook-examples.md +176 -0
- package/templates/shared/wecomcli-smartsheet/references/smart-sheet-webhook.md +169 -0
- package/templates/shared/wecomcli-todo/SKILL.md +76 -0
- package/templates/shared/wecomcli-todo/references/todo-create.md +137 -0
- package/templates/shared/wecomcli-todo/references/todo-delete.md +63 -0
- package/templates/shared/wecomcli-todo/references/todo-finish.md +72 -0
- package/templates/shared/wecomcli-todo/references/todo-get.md +66 -0
- package/templates/shared/wecomcli-todo/references/todo-list.md +133 -0
- package/templates/shared/wecomcli-todo/references/todo-update.md +112 -0
- package/templates/staff/design/AGENTS.md +2 -1
- package/templates/staff/ecommerce/.agents/skills/ops-ecommerce/SKILL.md +6 -0
- package/templates/staff/ecommerce/AGENTS.md +49 -0
- package/templates/staff/ecommerce/BOOTSTRAP.md +23 -0
- package/templates/staff/ecommerce/IDENTITY.md +8 -0
- package/templates/staff/ecommerce/MEMORY.md +9 -0
- package/templates/staff/ecommerce/PRIORITIES.md +3 -0
- package/templates/staff/ecommerce/SOUL.md +5 -0
- package/templates/staff/ecommerce/USER.md +8 -0
- package/templates/staff/hr/.agents/skills/staff-onboard-keys/SKILL.md +3 -3
- package/templates/staff/publish/.agents/skills/ops-publish/SKILL.md +6 -0
- package/templates/staff/publish/AGENTS.md +59 -0
- package/templates/staff/publish/BOOTSTRAP.md +23 -0
- package/templates/staff/publish/IDENTITY.md +8 -0
- package/templates/staff/publish/MEMORY.md +9 -0
- package/templates/staff/publish/PRIORITIES.md +3 -0
- package/templates/staff/publish/SOUL.md +6 -0
- package/templates/staff/publish/USER.md +8 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# calendar schedules free list — 查询参与人共同空闲
|
|
2
|
+
|
|
3
|
+
查询同企业成员在指定时间窗口内的共同空闲时段。直接返回可推荐的时段列表。
|
|
4
|
+
|
|
5
|
+
## 输出前必检(CRITICAL)
|
|
6
|
+
|
|
7
|
+
**任何 free list 触发的回复,最终对外文本都必须满足**:
|
|
8
|
+
- 不出现 `wo` 前缀字符串(userid 仅用于工具调用,对用户只显示姓名 / 别名)
|
|
9
|
+
- 不出现 `mt_` / `td_` / `wo_` / `doc_` / `room_` 等内部 ID 前缀
|
|
10
|
+
|
|
11
|
+
多人查询时尤其容易在"对齐姓名↔userid"中无意泄露——展示阶段如果你写到 `wo` 字符,
|
|
12
|
+
**立即停下重写**,只保留姓名(来自 `available_users[].name`)。
|
|
13
|
+
|
|
14
|
+
## 命令示例
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# 查询 woxxx 和 woyyy 在 2026-04-07 09:00:00 和 2026-04-07 18:00:00 之间的空闲时段,并且必须是60分钟整块的
|
|
18
|
+
wecom-cli calendar schedules free list --json '{
|
|
19
|
+
"userids": [{"userid": "woxxx"}, {"userid": "woyyy"}],
|
|
20
|
+
"begin_time": "2026-04-07 09:00:00",
|
|
21
|
+
"end_time": "2026-04-07 18:00:00",
|
|
22
|
+
"min_duration_minutes": 60,
|
|
23
|
+
"limit": 5
|
|
24
|
+
}'
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 参数
|
|
28
|
+
|
|
29
|
+
| 参数 | 类型 | 必填 | 默认 | 说明 |
|
|
30
|
+
|------|------|:----:|------|------|
|
|
31
|
+
| `userids` | object[] | 是 | — | >=1 个成员,对象数组格式 `[{"userid": "woxxx"}]`(`wo` 前缀)。允许单人调用,等价于"某人什么时候有空"查询 |
|
|
32
|
+
| `begin_time` | string | 是 | — | 查询窗口起,格式 `YYYY-MM-DD HH:mm:ss`。早于服务端当前时刻的部分会被自动截断 |
|
|
33
|
+
| `end_time` | string | 是 | — | 查询窗口止,必须晚于 `begin_time`,且与 `begin_time` 的间隔 ≤ 24 小时 |
|
|
34
|
+
| `min_duration_minutes` | int | 否 | `30` | 过滤掉短于该值的空闲段,避免推荐过碎的时间窗 |
|
|
35
|
+
| `strategy` | string | 否 | `max_attendees` | 推荐策略,详见下表 |
|
|
36
|
+
| `limit` | int | 否 | `10` | 返回时段数量上限 |
|
|
37
|
+
|
|
38
|
+
### `strategy` 取值
|
|
39
|
+
|
|
40
|
+
| 值 | 行为 | 状态 |
|
|
41
|
+
|----|------|------|
|
|
42
|
+
| `max_attendees` | 按最多可参与人数筛选,只返回最高一档人数的所有时段,同档内按时间升序。有共同空闲时即全员到场窗口;无共同空闲时自然降级为次大可达人数。 | 当前唯一实现,默认值 |
|
|
43
|
+
|
|
44
|
+
## 返回结构
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"total_count": 2,
|
|
49
|
+
"strategy": "max_attendees",
|
|
50
|
+
"extra_info": "没有找到所有人都空闲的时段,下面是符合 strategy 规则的时间段",
|
|
51
|
+
"slots": [
|
|
52
|
+
{
|
|
53
|
+
"begin_time": "2026-04-07 13:00:00",
|
|
54
|
+
"end_time": "2026-04-07 14:00:00",
|
|
55
|
+
"available_users": [
|
|
56
|
+
{"userid": "woxxx", "name": "张三"},
|
|
57
|
+
{"userid": "woyyy", "name": "李四"}
|
|
58
|
+
],
|
|
59
|
+
"available_count": 2,
|
|
60
|
+
"busy_users": []
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
| 字段 | 类型 | 说明 |
|
|
67
|
+
|------|------|------|
|
|
68
|
+
| `total_count` | int | 本次查询的有效人数 |
|
|
69
|
+
| `strategy` | string | 服务端实际采用的策略 |
|
|
70
|
+
| `extra_info` | string | 服务端提示文案。**降级场景**会说明"没有全员都空闲,下面是按 strategy 筛选的最佳时段"等内容,可作为措辞参考 |
|
|
71
|
+
| `slots[]` | array | 推荐的空闲时段,已按策略筛选、已过滤过去时段、已应用 `min_duration_minutes` |
|
|
72
|
+
| `slots[].begin_time` | string | 时段起始时间,格式 `YYYY-MM-DD HH:mm:ss`,与请求参数同格式,可直接展示 |
|
|
73
|
+
| `slots[].end_time` | string | 时段结束时间,格式 `YYYY-MM-DD HH:mm:ss` |
|
|
74
|
+
| `slots[].available_users` | array | 该时段内空闲的人(`userid` + `name`)。**展示时只用 `name`,禁止暴露 userid** |
|
|
75
|
+
| `slots[].available_count` | int | 该时段内空闲人数 |
|
|
76
|
+
| `slots[].busy_users` | array | 该时段内忙碌的人(`userid` + `name`)。`max_attendees` 全员命中时为空,降级时列出冲突人 |
|
|
77
|
+
|
|
78
|
+
> 展示时段前心算一次 `end_time - begin_time` 的分钟数,确认 ≥ 请求传入的
|
|
79
|
+
> `min_duration_minutes`(默认 30),避免把短时段的时长说宽。
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
### 指定重要优先人物优先的查询
|
|
83
|
+
|
|
84
|
+
如果用户希望查询一批人的空闲时间,但是优先其中某个子集(重要人物)必须空闲(不重要的人可以不空闲导致缺席),可以先单独查询重要人物的空闲时间,再查询全员的空闲时间。再推荐一个合适的时间。
|
|
85
|
+
|
|
86
|
+
### 分支判断(一次请求覆盖三种情况)
|
|
87
|
+
|
|
88
|
+
拿到响应后,比较 `slots[0].available_count` 与 `total_count`:
|
|
89
|
+
|
|
90
|
+
| 情况 | 含义 | Agent 行为 |
|
|
91
|
+
|------|------|-----------|
|
|
92
|
+
| `slots[0].available_count == total_count` | 存在全员共同空闲 | 展示所有可用时段让用户选择 |
|
|
93
|
+
| `0 < slots[0].available_count < total_count` | 无全员共同空闲,服务端已降级到"最多人能到"的窗口 | **先告知用户哪些人冲突、几人能参加**,再展示时段,让用户决定继续还是换时间 |
|
|
94
|
+
| `slots == []` | 查询窗口内没有任何符合最小粒度的可用时段 | 不要硬推荐,引导用户**扩大时间范围或减少参与人** |
|
|
95
|
+
|
|
96
|
+
> 一次请求已覆盖正常 / 降级 / 全忙三种语义,**不要发起第二次"降级查询"**。
|
|
97
|
+
|
|
98
|
+
> **查询"某时段有没有空"时,忙碌也要如实响应**:当用户问的是特定时间段的忙闲(如"张三下午 3 点有空吗""明天上午大家都在吗"),若该时段没有空闲(`slots` 为空)、或被问的人不在该时段的 `available_users` 里,必须明确回复"该时段忙 / 已有安排",并尽量点明是谁忙(取 `busy_users[].name`)、忙在哪一段;不要只报空闲时段,也不要用"无共同空闲"一笔带过而不点明忙碌状态。
|
|
99
|
+
|
|
100
|
+
### 切片与展示
|
|
101
|
+
|
|
102
|
+
- **推荐时段按 1 小时维度切分**:`slots` 返回的可用空闲段,若长度超过 1 小时,须在 Agent 侧按 1 小时粒度切成多个候选时段分别推荐(如空闲段 `15:00-18:00` 切为 `15:00-16:00`、`16:00-17:00`、`17:00-18:00`),每个候选统一按整 1 小时呈现;不足 1 小时的空闲段按其实际长度原样展示。查询时建议传 `min_duration_minutes=60`,避免推荐出不足 1 小时的碎片段。
|
|
103
|
+
- **候选起点不得越界(起点 ≤ 段终点 − 日程时长)[REQUIRED]**:候选切片的长度只是展示粒度,用户选中后实际占用的是「起点 + 完整日程时长」。因此当日程时长 D 超过 1 小时时,必须剔除那些「起点 + D」会超出本空闲段终点的候选起点——即候选起点必须满足 `起点 ≤ 段终点 − D`,否则实际区间会落到未经忙闲验证的时段、可能与他人冲突。例如 **2 小时**会议、空闲段 `15:00-18:00`:合法起点上限为 `18:00 − 2h = 16:00`,故只保留 `15:00`、`16:00` 两个起点(对应实际区间 `15:00-17:00`、`16:00-18:00`),必须剔除 `17:00`(其实际区间 `17:00-19:00` 已越过 18:00)。当空闲段长度本身小于 D 时,该段不产生任何候选。
|
|
104
|
+
- **推荐时段的长度只表示"这段时间可用",不代表日程/会议时长**:切出的 1 小时候选仅用于给用户挑选开始时段,用户选定后,日程/会议的实际时长仍以用户明确指定的为准;用户未明确时长时一律默认 1 小时(见 [calendar-create](calendar-create.md) 与 wecomcli-meeting 创建文档),禁止把推荐时段的长度直接当作时长。
|
|
105
|
+
|
|
106
|
+
### 输出格式
|
|
107
|
+
|
|
108
|
+
**情况 1:全员共同空闲**
|
|
109
|
+
```
|
|
110
|
+
推荐时间:
|
|
111
|
+
方案 1: 04-07 15:00-16:00 — 张三、李四都有空
|
|
112
|
+
方案 2: 04-07 16:00-17:00 — 张三、李四都有空
|
|
113
|
+
方案 3: 04-07 13:00-14:00 — 张三、李四都有空
|
|
114
|
+
|
|
115
|
+
选哪个方案?或者说"换一批"看其他时间。
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**情况 2:降级(部分人能参加)**
|
|
119
|
+
```
|
|
120
|
+
当前时间范围内没有所有人都空闲的时段,最多 2 人能到。
|
|
121
|
+
|
|
122
|
+
方案 1: 04-07 15:00-16:00 — 张三、李四能参加(王五此时有日程)
|
|
123
|
+
方案 2: 04-07 17:00-18:00 — 张三、李四能参加(王五此时有日程)
|
|
124
|
+
|
|
125
|
+
要按这些时段安排吗?或者换个时间窗口让王五也能参加?
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**情况 3:全员无空**
|
|
129
|
+
```
|
|
130
|
+
04-07 13:00-18:00 内,张三、李四、王五 没有任何能凑齐的空闲时段(最小粒度 30 分钟)。
|
|
131
|
+
|
|
132
|
+
建议:
|
|
133
|
+
1. 扩大时间窗口(如延长到傍晚或换一天)
|
|
134
|
+
2. 减少参与人
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
> 展示参与人时只用姓名。`available_users[].userid` 仅用于回传到 `schedules create` 的 `attendees`,禁止出现在面向用户的文案里。
|
|
138
|
+
|
|
139
|
+
## 典型场景
|
|
140
|
+
|
|
141
|
+
### 1. 有共同空闲时段
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
用户:帮我约张三和李四明天下午聊一下
|
|
145
|
+
→ 通过 wecomcli-contact 技能批量搜索「张三」「李四」,解析为 userid
|
|
146
|
+
→ 调用 free list(明天 13:00-18:00;`userids` = 自己 + 张三 + 李四——新建日程的共同空闲须把自己也纳入,避免排到自己已占用的时段)
|
|
147
|
+
→ slots[0].available_count == total_count == 3,存在全员共同空闲
|
|
148
|
+
→ 展示前 3 个时段让用户选择
|
|
149
|
+
→ 用户选择 → 调用 create
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 2. 部分降级 / 全员无空
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
用户:帮我约王五和赵六、孙七明天上午碰一下
|
|
156
|
+
→ 通过 wecomcli-contact 技能批量搜索,解析为 userid
|
|
157
|
+
→ 调用 free list(明天 09:00-12:00)
|
|
158
|
+
→ 情况 A: slots 为空 → 引导扩大窗口或减少参与人
|
|
159
|
+
→ 情况 B: slots[0].available_count = 2 < 3 → 告知冲突的人和"最多 2 人能参加"的时段
|
|
160
|
+
→ 用户选"换个时间" → 重新追问范围 → 再次调用
|
|
161
|
+
→ 用户选"按 2 人安排" → 调用 create(只把 available_users 中的人作为参与人)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### 3. 单人空闲查询
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
用户:李四明天什么时候有空
|
|
168
|
+
→ 通过 wecomcli-contact 技能搜索「李四」,解析为 userid
|
|
169
|
+
→ 调用 free list(userids 单元素,begin_time/end_time 覆盖明天工作时段)
|
|
170
|
+
→ slots 即李四的空闲段
|
|
171
|
+
→ 用人话展示时段起止时间
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 加人 / 改时间到已有日程时的查询对象(避免自冲突误报)[CRITICAL]
|
|
175
|
+
|
|
176
|
+
为"已存在的日程"加人或改时间而做忙闲检查时,查询对象**必须排除正被该日程占用、因而必然显示忙碌的人和时间段**,否则会误报冲突。
|
|
177
|
+
|
|
178
|
+
**核心原则**:对【已在本日程中的人】(日程创建者 / 自己 + 已有参与人)只查"与本日程**当前时段不重叠**"的时间——本日程已占着原时段,对这些人在原时段查到的"忙"是它自己造成的自冲突误报;【新增参与人】才查完整目标时段。据此分三种情况:
|
|
179
|
+
|
|
180
|
+
- **① 只加人、不改时间** → `userids` 只放**新增参与人**,针对**日程原时段**查询。**不要**把当前用户(创建者 / 自己)和已有参与人放进 `userids`——他们正因这条日程而"忙",纳入后会误判为冲突,而用户本意恰恰是让别人加入自己这个已定时间的日程。
|
|
181
|
+
- **② 改时间,且新时段与原时段【不重叠】**(平移 / 改期,如 15:00 改到 17:00)→ `userids` 放"改后仍需参加的人 + 新增参与人",针对**新时段**查询。新旧时段无交集,现有参与人查新时段不会撞上本日程,可正常纳入。
|
|
182
|
+
- **③ 改时间,且新时段与原时段【有重叠】**(延长 / 提前等,新时段含部分原时段)→ 不能整段查现有参与人,否则重叠部分会被本日程自己误报为忙:
|
|
183
|
+
- **新增参与人**:查**完整新时段**。
|
|
184
|
+
- **现有参与人及自己**:只查**新时段去掉与原时段重叠后剩下的增量段**(如 15:00-16:00 延到 15:00-17:00,只查 16:00-17:00;如 15:00-16:00 提前到 14:00-16:00,只查 14:00-15:00)。增量段为空(如仅缩短时间)则现有参与人无需查。
|
|
185
|
+
|
|
186
|
+
> 该约束同样适用于 [calendar-update](calendar-update.md) 的"参与人变更工作流":先按上述规则圈定查询对象和查询时段,再调用 `free list`。
|
|
187
|
+
|
|
188
|
+
## 查询范围约束
|
|
189
|
+
|
|
190
|
+
- **必须传未来时间**:`begin_time` 早于服务端当前时刻的部分会被自动截断;传纯历史窗口会得到空 `slots`。
|
|
191
|
+
**调用前先检查**:若用户问"昨天 / 上周 / 上个月某人什么时候有空"等纯过去时间,直接告知用户"过去时段无法查询忙闲"并引导改成未来时间,不要先调 `free list` 拿到空结果再解释。
|
|
192
|
+
- **单次窗口 ≤ 24 小时**:`end_time` 必须晚于 `begin_time` 且间隔不超过 24h。跨天 / 多天需求必须拆成多段分别调用,再在 Agent 侧按顺序拼接 slots。
|
|
193
|
+
- **未给时间窗口的默认值**:用户只问"X 什么时候有空"没给日期范围时,默认只查当天剩余工作时段 + 明天工作时段(共两个 24h 窗口),不要主动展开 3 天以上——若不够再询问用户。
|
|
194
|
+
- **周期日程限制**:仅覆盖最近两个月有修改的周期日程,更早的可能不在结果中。
|
|
195
|
+
- **隐私保留**:返回中不包含日程主题、描述、其他参与人;只暴露忙 / 闲的归属人。
|
|
196
|
+
|
|
197
|
+
## 异常处理
|
|
198
|
+
|
|
199
|
+
| 异常场景 | 处理方式 |
|
|
200
|
+
|---------|---------|
|
|
201
|
+
| 接口调用失败 | 告知"忙闲查询暂时不可用",建议用户直接确认时间后创建日程 |
|
|
202
|
+
| `slots == []` 且窗口合理 | 引导用户扩大时间窗口或减少参与人,不要重复传同一窗口试错 |
|
|
203
|
+
|
|
204
|
+
## 参考
|
|
205
|
+
|
|
206
|
+
- [wecomcli-calendar](../SKILL.md) — 日程技能主文档
|
|
207
|
+
- [calendar-create](calendar-create.md) — 创建日程
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# calendar 会议室查询 — buildings list / rooms search
|
|
2
|
+
|
|
3
|
+
查询办公楼清单(`buildings list`)和会议室可订性(`rooms search`),用于日程/会议创建或更新时选会议室。两者均为**只读查询**,真正的占用在 [calendar-create](calendar-create.md) 创建时传 `meeting_room_id`、或在 update([日程](calendar-update.md) / [会议](../../wecomcli-meeting/references/meeting-update.md))改订时传 `meeting_room_id` 完成。
|
|
4
|
+
|
|
5
|
+
> 本文档是会议室查询的唯一信息源,[wecomcli-meeting 技能](../../wecomcli-meeting/SKILL.md) 创建会议时也引用此处。
|
|
6
|
+
|
|
7
|
+
## 命令
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# 列出我可访问的办公楼
|
|
11
|
+
wecom-cli meeting rooms buildings list --json '{}'
|
|
12
|
+
|
|
13
|
+
# 查会议室可订性(单时段)
|
|
14
|
+
wecom-cli meeting rooms search --json '{
|
|
15
|
+
"begin_time": "<日期> 14:00:00",
|
|
16
|
+
"end_time": "<日期> 15:00:00",
|
|
17
|
+
"room_keyword": "1605",
|
|
18
|
+
"floor_name": "16",
|
|
19
|
+
"min_capacity": 4
|
|
20
|
+
}'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## buildings list — 办公楼清单
|
|
26
|
+
|
|
27
|
+
返回用户可访问的办公楼全量列表,无入参(传 `{}`)。
|
|
28
|
+
|
|
29
|
+
### 返回结构
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"total_count": 3,
|
|
34
|
+
"buildings": [
|
|
35
|
+
{ "name": "创新大厦A座", "city": "北京", "is_current": true },
|
|
36
|
+
{ "name": "创新大厦B座", "city": "北京", "is_current": false },
|
|
37
|
+
{ "name": "滨海科技园", "city": "上海", "is_current": false }
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
| 字段 | 说明 |
|
|
43
|
+
|------|------|
|
|
44
|
+
| `total_count` | `buildings` 数组长度 |
|
|
45
|
+
| `buildings[].name` | 建筑本名,不含城市前缀 |
|
|
46
|
+
| `buildings[].city` | 城市,展示时拼 `${city} ${name}` |
|
|
47
|
+
| `buildings[].is_current` | 当前所在楼标记;无法判断时全为 `false` |
|
|
48
|
+
|
|
49
|
+
> 无内部 building_id;下游 `rooms search` 引用某栋楼时传 `building_city` + `building_name`。
|
|
50
|
+
|
|
51
|
+
### 用法
|
|
52
|
+
|
|
53
|
+
- **仅当用户提到楼名时调用**;没提楼则不调用,让 `rooms search` 用当前所在楼兜底。
|
|
54
|
+
- 把用户口语楼名(如"北京创新A")匹配到列表条目,得到 `city` + `name`。
|
|
55
|
+
- 多候选 → 用文字让用户选(展示用 `${city} ${name}`);无匹配 → 告知不在可访问列表并列出可选项。
|
|
56
|
+
- `buildings: []` → 提示"暂无可预订办公地点"。
|
|
57
|
+
|
|
58
|
+
> **楼栋识别靠模糊匹配 + 确认,不要苛求字面一致,也不要罗列充数:**
|
|
59
|
+
> - 用户说的楼名往往与 `buildings list` 的标准名**写法不同**(使用简称、漏字、少写 A/B 座、带或不带城市前缀等)。应把用户表述与返回列表做**模糊匹配**,而不是要求逐字相同。
|
|
60
|
+
> - 命中**唯一最接近**的条目 → 用文字确认一句"你是指【${city} ${name}】吗?",确认后用该条目的 `city`+`name` 调 `rooms search`。
|
|
61
|
+
> - 命中**多个相近**条目 → 用文字只列这几个(展示用 `${city} ${name}`)让用户选。
|
|
62
|
+
> - **确实匹配不到**(用户没给楼线索,或列表里没有相近项)→ 才让用户补充 / 自由输入楼名;**禁止从全量列表里随机挑几个充数,也禁止凭记忆编造列表里没有的楼名**。
|
|
63
|
+
> - 展示给用户的楼名、以及最终喂给 `rooms search` 的 `building_name` / `building_city`,都必须**逐字取自 `buildings list` 的返回条目**。
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## rooms search — 会议室可订性查询
|
|
68
|
+
|
|
69
|
+
给定单时段 + 可选会议室提示 + 容量需求,返回目标会议室能否预订及同楼候选。
|
|
70
|
+
|
|
71
|
+
### 参数
|
|
72
|
+
|
|
73
|
+
| 参数 | 类型 | 必填 | 默认 | 说明 |
|
|
74
|
+
|------|------|:----:|------|------|
|
|
75
|
+
| `begin_time` | string | 是 | — | `YYYY-MM-DD HH:mm:ss`,必须晚于当前时刻 |
|
|
76
|
+
| `end_time` | string | 是 | — | 晚于 `begin_time`,间隔 ≤ 24h |
|
|
77
|
+
| `building_city` | string | 否 | 当前所在楼城市 | 与 `building_name` 同传或同省略 |
|
|
78
|
+
| `building_name` | string | 否 | 当前所在楼楼名 | 同上 |
|
|
79
|
+
| `room_keyword` | string | 否 | — | 会议室名/号关键词(如 `"1605"`、`"创新室"`) |
|
|
80
|
+
| `floor_name` | string | 否 | — | 楼层过滤,按楼层名匹配(如 `"16"`、`"3 楼"`),仅返回该楼层的会议室;用户明确指定楼层时传入,**直接使用用户的原始表述传入,不做归一化/转换**(用户说"16 楼"就传 `"16 楼"`,说"16F"就传 `"16F"`) |
|
|
81
|
+
| `min_capacity` | int | 否 | `2` | 容量下限,传 `len(attendees) + 1`(含组织者) |
|
|
82
|
+
| `expand_to_other_buildings` | bool | 否 | `false` | `true` 时同城跨楼推荐,仅用户明确要求才传 |
|
|
83
|
+
| `limit` | int | 否 | `20` | `recommendations` 上限(最大 100) |
|
|
84
|
+
|
|
85
|
+
> `building_city/name` 均不传时用当前所在楼兜底;兜底失败返回 `current_building_unknown`。
|
|
86
|
+
|
|
87
|
+
### 返回结构
|
|
88
|
+
|
|
89
|
+
传了 `room_keyword` 时 `target` 为命中的目标会议室列表(数组,每项含 `status`:`bookable` / `unavailable` / `not_found`;同一关键词或叠加 `floor_name` 楼层过滤可能命中多间),未传 `room_keyword` 时 `target` 为空数组 `[]`。`recommendations` 为同楼候选。
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"inferred_building": { "name": "创新大厦A座", "city": "北京", "source": "user_current" },
|
|
94
|
+
"target": [
|
|
95
|
+
{
|
|
96
|
+
"status": "unavailable",
|
|
97
|
+
"room": { "meeting_room_id": "mrmaaa", "name": "1605", "capacity": 6, "floor": "16F" }
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
"recommendations": [
|
|
101
|
+
{ "meeting_room_id": "mrmbbb", "name": "1607", "capacity": 6, "floor": "16F" },
|
|
102
|
+
{ "meeting_room_id": "mrmccc", "name": "1608", "capacity": 8, "floor": "16F" }
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
| 字段 | 说明 |
|
|
108
|
+
|------|------|
|
|
109
|
+
| `inferred_building.name/city` | 实际查询的办公楼,可展示给用户确认 |
|
|
110
|
+
| `inferred_building.source` | `user_current`(兜底)或 `from_input`(来自入参) |
|
|
111
|
+
| `target` | 目标会议室列表(数组);传 `room_keyword` 时为命中项(可能多间),未传为空数组 `[]` |
|
|
112
|
+
| `target[].status` | `bookable` / `unavailable` / `not_found` |
|
|
113
|
+
| `target[].room` | `not_found` 时为 `null`,否则为房间元数据 |
|
|
114
|
+
| `recommendations[]` | 同楼候选,已按"同楼层优先 → 容量恰好够用"排序 |
|
|
115
|
+
| `recommendations[].meeting_room_id` | 会议室 ID,仅工具链使用,禁止出现在用户回复正文 |
|
|
116
|
+
|
|
117
|
+
### 边界
|
|
118
|
+
|
|
119
|
+
- `target[].status = unavailable` 时不返回占用方信息。
|
|
120
|
+
- 同楼无可用时 `recommendations: []`,由 Agent 决定是否开 `expand_to_other_buildings`。
|
|
121
|
+
- `meeting_room_id` 仅在工具调用间流转,对用户只展示会议室 name。
|
|
122
|
+
|
|
123
|
+
### 错误码
|
|
124
|
+
|
|
125
|
+
| code | 触发场景 | 处理 |
|
|
126
|
+
|------|---------|------|
|
|
127
|
+
| `current_building_unknown` | 未传楼且无法兜底 | 调 `buildings list` 让用户选楼后重试 |
|
|
128
|
+
| `building_not_found` | 入参楼名查无匹配 | 提示该楼无权限,列出可选项 |
|
|
129
|
+
| `time_in_past` | `begin_time` ≤ 当前时刻 | 提示用户改未来时间 |
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Agent 侧编排
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
├─ 用户提了楼名 → buildings list → 匹配 → building_city + building_name
|
|
137
|
+
│ 用户没提楼 → 跳过(rooms search 用当前所在楼兜底)
|
|
138
|
+
│
|
|
139
|
+
└─ rooms search(begin/end + 可选楼 + 可选 room_keyword + min_capacity = len(attendees)+1)
|
|
140
|
+
├─ 用户指定了具体会议室(传了 room_keyword)→ target 为命中列表:
|
|
141
|
+
│ ├─ target 中存在 status = bookable 的会议室:
|
|
142
|
+
│ │ ├─ 仅 1 个 → 唯一确定,拿其 target[].room.meeting_room_id 进 create
|
|
143
|
+
│ │ └─ 多个 → 用文字让用户选(禁止自动取第一个)
|
|
144
|
+
│ ├─ target = [](查无此名 / 无命中)→ 先告知"未查到你指定的『xxx』会议室",禁止静默替换;
|
|
145
|
+
│ │ 再用文字让用户决定改订其他会议室或换时间(候选仅 1 个也须用户确认);recommendations 为空则告知后问换时间/跨楼
|
|
146
|
+
│ └─ target 中无 bookable、命中项均为 unavailable(被占)→ 先告知"『xxx』该时段已被占用",
|
|
147
|
+
│ 再用文字让用户选替代会议室或换时间(同样禁止静默替换)
|
|
148
|
+
├─ 用户未指定具体会议室(target = []):
|
|
149
|
+
│ ├─ recommendations 多个候选 → 必须用文字让用户选(禁止自动取第一个)
|
|
150
|
+
│ └─ recommendations 仅 1 个 → 可直接使用该候选 meeting_room_id
|
|
151
|
+
└─ recommendations = [] → 问是否跨楼(expand_to_other_buildings=true 重试)或换时间
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
> [!CAUTION]
|
|
155
|
+
> **五条硬性规则(下游 create 必须遵守):**
|
|
156
|
+
> 1. **先查询、后推荐、后创建**:`meeting_room_id` 必须来自 `rooms search` 的真实返回值,禁止跳过查询直接创建,禁止凭记忆 / 猜测编造。任何向用户展示的候选 / 推荐会议室(含用文字给出的候选、回复正文里提到的会议室名 / 房间号 / 楼层 / 容量)也必须来自本次 `rooms search` 返回的 `target` / `recommendations`——在成功调用 `rooms search` 拿到真实结果之前,禁止凭记忆、上下文、历史会话或想象罗列、推荐、列举任何具体会议室让用户选择。需要让用户选会议室时,先调 `rooms search`,再用其返回的候选组装文字询问。
|
|
157
|
+
> 2. **存在多个会议室必须让用户选**:`recommendations` 命中多个候选时,必须用文字让用户选择或指定具体会议室,禁止自动替用户挑选。
|
|
158
|
+
> 3. **会议室禁止只写进 `location`**:只要用户提到会议室,就必须经 `rooms search` 查到真实会议室并以 `meeting_room_id` 传入创建。严禁把会议室名 / 房间号仅写进 `location` 字段——那样不会真正占用(预订)会议室。
|
|
159
|
+
> 4. **优先先订房、后建程/建会**:用户在创建时就提到会议室的,应先敲定 `meeting_room_id`(含用户确认)再调用 create,会议室查询/选择是 create 的前置阻塞项,避免创建后会议室被抢占。若创建时漏订或事后要换会议室,可通过 `update` 传入新 `meeting_room_id` 改订(须先经 `rooms search` 确认新会议室 `status=bookable`,详见各自的 update 参考),不必取消重建。
|
|
160
|
+
> 5. **指定会议室查无/不可用时必须先告知、禁止静默替换**:用户指定的会议室在 `target` 中找不到可订项(`target = []` 查无此名,或命中项均为 `unavailable` 被占)时,必须先告知用户"未查到 / 无法预订你指定的『xxx』会议室",再用文字让用户决定改订其他会议室或换时间。严禁静默用其他名称的会议室替代——即使 `recommendations` 仅 1 个候选也须经用户确认。"`recommendations` 仅 1 个可直接使用"只适用于用户未指定具体会议室(`target = []`)的情形。
|
|
161
|
+
|
|
162
|
+
- `rooms search` 需要**确定的起止时间**。用户只给了时间范围(如"明天下午")时,先用 [calendar-freebusy](calendar-freebusy.md) 查共同空闲、让用户选定一个具体时段,再拿该时段调 `rooms search`;用户已给精确时间(如"明天 3 点")则直接查。
|
|
163
|
+
- 用文字给出的候选必须 2~4 个,展示会议室 `name` + 楼层 + 容量;`meeting_room_id` 仅工具链使用,禁止出现在用户回复正文。
|
|
164
|
+
- `meeting_room_taken`(抢订竞态)发生在 create 阶段,处理见 [calendar-create](calendar-create.md)。
|
|
165
|
+
|
|
166
|
+
## 参考
|
|
167
|
+
|
|
168
|
+
- [calendar-create](calendar-create.md) — 日程创建(传 `meeting_room_id` 占用会议室)
|
|
169
|
+
- [calendar-freebusy](calendar-freebusy.md) — 共同空闲查询
|
|
170
|
+
- [wecomcli-calendar.md](../SKILL.md) — 日程技能主文档
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# calendar schedules search — 搜索日程
|
|
2
|
+
|
|
3
|
+
按关键词、组织人或参与人搜索用户发起和参与的日程。
|
|
4
|
+
|
|
5
|
+
> [!CAUTION]
|
|
6
|
+
> **`schedules search` 必须翻页到底**:返回中只要 `has_more == true`,就必须携带 `next_cursor` 再次调用 search,循环直到 `has_more == false`,否则会漏数据;禁止只取第一页就提前终止。
|
|
7
|
+
|
|
8
|
+
> **模糊搜索同时搜会议 [REQUIRED]**:若用户搜的是"会 / xx会 / xx会议"等模糊目标(非明确日程,见 [SKILL.md 查询消歧](../SKILL.md)),除按关键词搜日程外,必须同时 `读取 wecomcli-meeting 技能` 用同样关键词搜会议,把两边结果合并、分「(会议)」「(日程)」汇总展示——不论日程是否搜到都要搜会议。明确是日程 / 安排时只搜日程。
|
|
9
|
+
|
|
10
|
+
## 命令
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# 按关键词搜索
|
|
14
|
+
wecom-cli calendar schedules search --json '{"keywords": ["项目评审"]}'
|
|
15
|
+
|
|
16
|
+
# 按关键词搜索(用户明确指定时间范围)
|
|
17
|
+
wecom-cli calendar schedules search --json '{"keywords": ["周会"], "begin_time": "2026-04-07 00:00:00", "end_time": "2026-04-07 23:59:59"}'
|
|
18
|
+
|
|
19
|
+
# 按组织人搜索
|
|
20
|
+
wecom-cli calendar schedules search --json '{"organizer": "woxxx"}'
|
|
21
|
+
|
|
22
|
+
# 按参与人搜索
|
|
23
|
+
wecom-cli calendar schedules search --json '{"has_attendees": [{"userid": "woxxx"}, {"userid": "woyyy"}]}'
|
|
24
|
+
|
|
25
|
+
# 分页搜索
|
|
26
|
+
wecom-cli calendar schedules search --json '{"keywords": ["周会"], "cursor": "CURSOR_TOKEN", "limit": 50}'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 参数
|
|
30
|
+
|
|
31
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
32
|
+
|------|------|:----:|------|
|
|
33
|
+
| `keywords` | string[] | 三选一 | 搜索关键词数组,可匹配日程主题、会议室名称等信息(关键词、组织人、参与人至少传入其一) |
|
|
34
|
+
| `organizer` | string | 三选一 | 组织人 userid(关键词、组织人、参与人至少传入其一) |
|
|
35
|
+
| `has_attendees` | object[] | 三选一 | 参与人列表,对象数组格式 `[{"userid": "woxxx"}]`(关键词、组织人、参与人至少传入其一)。需传入查询涉及的**所有参与人,包括当前用户自己**,不要只传别人而漏掉自己 |
|
|
36
|
+
| `begin_time` | string | 否 | 搜索区间起始时间(格式 YYYY-MM-DD HH:mm:ss) |
|
|
37
|
+
| `end_time` | string | 否 | 搜索区间结束时间(格式 YYYY-MM-DD HH:mm:ss) |
|
|
38
|
+
| `cursor` | string | 否 | 分页游标,首次请求不传,翻页时传上次返回的 `next_cursor` |
|
|
39
|
+
| `limit` | number | 否 | 单页返回数量,最大 50 |
|
|
40
|
+
|
|
41
|
+
> **必填约束**:`keywords`、`organizer`、`has_attendees` 三者至少传入一个,否则接口报错。
|
|
42
|
+
|
|
43
|
+
## 返回
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"schedules": [
|
|
48
|
+
{
|
|
49
|
+
"schedule_id": "SCHEDULE_ID",
|
|
50
|
+
"subject": "SUBJECT",
|
|
51
|
+
"begin_time": "YYYY-MM-DD HH:mm:ss",
|
|
52
|
+
"end_time": "YYYY-MM-DD HH:mm:ss",
|
|
53
|
+
"attendees": [
|
|
54
|
+
{
|
|
55
|
+
"userid": "USERID1",
|
|
56
|
+
"name": "englishname(name)"
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"meeting_room": {
|
|
60
|
+
"meeting_room_id": "MEETING_ROOM_ID",
|
|
61
|
+
"meeting_room_name": "MEETING_ROOM_NAME"
|
|
62
|
+
},
|
|
63
|
+
"meeting": {
|
|
64
|
+
"meeting_id": "MEETING_ID",
|
|
65
|
+
"meeting_code": "MEETING_CODE",
|
|
66
|
+
"meeting_link": "MEETING_LINK"
|
|
67
|
+
},
|
|
68
|
+
"location": "LOCATION",
|
|
69
|
+
"description": "CONTENT",
|
|
70
|
+
"creator_name": "NAME",
|
|
71
|
+
"cal_id": "CAL_ID",
|
|
72
|
+
"calendar_name": "CALENDAR_NAME",
|
|
73
|
+
"is_share_cal": false,
|
|
74
|
+
"allow_self_join": false,
|
|
75
|
+
"is_all_day": false,
|
|
76
|
+
"repeat_rule": { "is_repeat": false },
|
|
77
|
+
"reminders": { "is_remind": false, "reminder_time": [-900] },
|
|
78
|
+
"timezone": { "timezone_id": "Asia/Shanghai", "timezone_offset": 28800 }
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"schedules_count": 1,
|
|
82
|
+
"next_cursor": "xxx",
|
|
83
|
+
"has_more": false
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
| 字段 | 说明 |
|
|
88
|
+
|------|------|
|
|
89
|
+
| `schedules[].schedule_id` | 日程 ID |
|
|
90
|
+
| `schedules[].subject` | 日程主题 |
|
|
91
|
+
| `schedules[].begin_time` | 开始时间 |
|
|
92
|
+
| `schedules[].end_time` | 结束时间 |
|
|
93
|
+
| `schedules[].attendees[].userid` | 参与人 userid |
|
|
94
|
+
| `schedules[].attendees[].name` | 参与人姓名(格式:`englishname(中文名)`) |
|
|
95
|
+
| `schedules[].meeting_room.meeting_room_id` | 会议室 ID |
|
|
96
|
+
| `schedules[].meeting_room.meeting_room_name` | 会议室名称 |
|
|
97
|
+
| `schedules[].meeting` | 在线会议信息(关联了会议时才有),含 `meeting_id`/`meeting_code`/`meeting_link`;`meeting_code` 非空即「含在线会议链接的会议形态日程」 |
|
|
98
|
+
| `schedules[].location` | 日程地点 |
|
|
99
|
+
| `schedules[].description` | 日程描述 |
|
|
100
|
+
| `schedules[].creator_name` | 日程创建者名字 |
|
|
101
|
+
| `schedules[].cal_id` | 所属日历本 ID |
|
|
102
|
+
| `schedules[].calendar_name` | 日历本名称 |
|
|
103
|
+
| `schedules[].is_share_cal` | 所属日历是否为共享日历(日历创建者非当前用户) |
|
|
104
|
+
| `schedules[].allow_self_join` | 是否允许非参与人主动加入日程 |
|
|
105
|
+
| `schedules[].is_all_day` | 是否全天事件 |
|
|
106
|
+
| `schedules[].repeat_rule` | 周期规则,子字段(含 `is_repeat`/`repeat_type`/`repeat_until`/`exception[]` 等)与 [calendar-agenda](calendar-agenda.md) 的 `repeat_rule` 完全一致;`is_repeat=true` 即周期日程,可直接判定无需补 `get` |
|
|
107
|
+
| `schedules[].reminders` | 提醒设置,含 `is_remind`(bool)和 `reminder_time`(int[],与开始时间的差值秒数,负数为提前提醒) |
|
|
108
|
+
| `schedules[].timezone` | 时区信息,含 `timezone_id`(IANA 标识,如 `Asia/Shanghai`,优先使用)和 `timezone_offset`(UTC 偏移量秒数,`timezone_id` 为空时使用) |
|
|
109
|
+
| `schedules_count` | `schedules` 数组元素数量 |
|
|
110
|
+
| `next_cursor` | 下一页游标,翻页时作为 `cursor` 传入 |
|
|
111
|
+
| `has_more` | 是否还有更多数据 |
|
|
112
|
+
|
|
113
|
+
> **参与人姓名**:接口已在 `attendees[].name` 中直接返回姓名,**无需额外调用 wecomcli-contact 技能反查**。展示时直接使用 `name` 字段,禁止展示 `userid`。
|
|
114
|
+
|
|
115
|
+
> **判定会议形态 / 周期性无需补 `get` [REQUIRED]**:`search` 出参与 `list`/`get` 对齐,已含 `meeting`、`repeat_rule`、`reminders`、`timezone` 等字段——可直接用 `meeting.meeting_code` 非空判定「会议 / 纯日程」(用于分组展示、改约路由)、直接取 `meeting.meeting_id` 传给 `wecomcli-meeting`、直接用 `repeat_rule.is_repeat` 判定周期日程,**不必再补一次 `get`**。
|
|
116
|
+
|
|
117
|
+
## 搜索策略
|
|
118
|
+
|
|
119
|
+
**搜索条件策略**:
|
|
120
|
+
- 有日程名称/关键词 → 传 `keywords` 数组
|
|
121
|
+
- 用户提到"某人组织的日程" → 上下文中已有该人合法 userid 则直接使用,否则通过 `读取 wecomcli-contact 技能` 按姓名获取 userid,传 `organizer`
|
|
122
|
+
- 用户提到"某人参与的日程" → 上下文中已有该人合法 userid 则直接使用,否则通过 `读取 wecomcli-contact 技能` 按姓名获取 userid,传 `has_attendees`
|
|
123
|
+
|
|
124
|
+
**时间范围策略**:`begin_time` / `end_time` 均为选填。用户未明确指定时间时,不传时间参数;仅当用户明确说明时间范围时才传入。
|
|
125
|
+
|
|
126
|
+
**分页策略**:首次搜索不传 `cursor`;**只要返回 `has_more=true`,就必须携带 `next_cursor` 继续翻页,循环直到 `has_more=false` 把结果取全,禁止只取第一页就提前终止**(否则会漏数据、统计不准)。取全后再展示:超过 10 条时只展示和用户问题最相关的 10 条,并告知"还有 N 条,需要查看更多吗?"。
|
|
127
|
+
|
|
128
|
+
**接口选择规则**:
|
|
129
|
+
1. **有日程主题关键词 → `search`**:用户提到日程主题/关键词时,不追问时间,直接搜索。
|
|
130
|
+
2. **无日程主题关键词 → `list`**:用户泛泛说"看看日程",或只给了时间/日期时,一律用 `list` 按时间范围拉取;禁止把日期当 `keywords` 走 `search`。
|
|
131
|
+
3. **要详情 → `get`**:`search`/`list` 返回已含 `meeting`、`repeat_rule` 等字段,会议形态与周期性可直接判定,一般无需再调 `get`;仅在只拿到 `schedule_id`(无上下文结果)时用 `get` 补齐。
|
|
132
|
+
4. **与某人相关 → 优先 `search`**:寻找与某人相关的日程时,优先用 `search`(传 `has_attendees`/`organizer`,或把人名作为 `keywords`),而非 `list` 拉全量再过滤。
|
|
133
|
+
|
|
134
|
+
## 典型场景
|
|
135
|
+
|
|
136
|
+
### 1. 单个结果
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
用户:项目评审是什么时候?
|
|
140
|
+
→ 调用 search(keywords=["项目评审"],不传时间)
|
|
141
|
+
→ 找到 1 条 → 直接读取 attendees[].name 展示参与者姓名
|
|
142
|
+
→ 展示三项:主题、时间、参与人(禁止 markdown 表格)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 2. 多个结果
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
用户:最近有没有周会?
|
|
149
|
+
→ 调用 search(keywords=["周会"],不传时间)
|
|
150
|
+
→ 找到 3 条 → 用文字列出摘要供用户选择:
|
|
151
|
+
文字提问:"找到多个匹配日程,请选择要查看的一个:"
|
|
152
|
+
列出候选(如"周会 - 4月14日 10:00 / 周会 - 4月21日 10:00 / 周会 - 4月28日 10:00",最多 4 条)
|
|
153
|
+
→ 用户选择后调用 get 获取详情
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 3. 搜索无结果
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
用户:帮我找一下产品发布会的日程
|
|
160
|
+
→ 调用 search(keywords=["产品发布会"],不传时间)→ 无结果
|
|
161
|
+
→ 用文字告知用户未找到,提供以下恢复建议:
|
|
162
|
+
1. 更换关键词重试(日程名称可能不完全匹配)
|
|
163
|
+
2. 按组织人搜索(提供日程组织人姓名,将通过 wecomcli-contact 技能解析为 userid 后传 organizer)
|
|
164
|
+
3. 按参与人搜索(提供参与该日程的人员姓名,解析 userid 后传 has_attendees)
|
|
165
|
+
4. 补充时间范围(日程可能不在接口默认返回范围内)
|
|
166
|
+
→ 根据用户选择执行对应策略
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 4. 用户明确指定时间范围
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
用户:找一下4月份的周会
|
|
173
|
+
→ 调用 search(keywords=["周会"],begin_time="2026-04-01 00:00:00",end_time="2026-04-30 23:59:59")
|
|
174
|
+
→ 展示结果
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 5. 按组织人搜索
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
用户:帮我找一下张三组织的日程
|
|
181
|
+
→ 通过 wecomcli-contact 技能搜索"张三"获取 userid(如 woxxx)
|
|
182
|
+
→ 调用 search(organizer="woxxx")
|
|
183
|
+
→ 展示结果,参与人直接读 attendees[].name,创建者读 creator_name
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 6. 结果超过 10 条(分页)
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
→ 只要 has_more=true 就先用 next_cursor 翻页到底,取全所有结果(禁止提前终止)
|
|
190
|
+
→ 顺序输出前 10 条日程,每条只含主题/时间/参与人(禁止 markdown 表格)
|
|
191
|
+
→ 末尾告知"还有 N 条,需要查看更多吗?"
|
|
192
|
+
→ 用户确认后展示后续结果(已取回,无需再调接口)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## 注意事项
|
|
196
|
+
|
|
197
|
+
- **不传默认时间**:用户未明确指定时间时,不传 `begin_time` / `end_time`;仅当用户明确说明时间时才传入。
|
|
198
|
+
- **不追问时间**:用户提供了关键词时,直接搜索,不要追问"你说的是什么时候的"。
|
|
199
|
+
- **参与人展示**:search 返回的 `attendees[].name` 已包含姓名,直接使用,无需调用 wecomcli-contact 技能反查。禁止展示 `userid`。
|
|
200
|
+
- **列表展示规范 [REQUIRED]**:多条结果时按 [SKILL.md 输出格式规范](../SKILL.md) 的「日程列表展示规范」处理——禁止 markdown 表格,每条作为独立条目顺序输出,每个条目只含主题/时间/参与人,超过 10 条只展示前 10 条并告知"还有 N 条,需要查看更多吗?"。
|
|
201
|
+
- **时区标注**:日程 `timezone.timezone_offset != 28800`(非东八区)时,按 [SKILL.md 输出格式规范](../SKILL.md) 的时区标注规则在时间后带上时区,如 `14:00-15:00(纽约时间 UTC-5)`。
|
|
202
|
+
|
|
203
|
+
## 参考
|
|
204
|
+
|
|
205
|
+
- [wecomcli-calendar](../SKILL.md) — 日程技能主文档
|
|
206
|
+
- [calendar-agenda](calendar-agenda.md) — 查看日程安排
|