🎯 Learning objectives
Two new FunctionTools
list_free_slots and book_event against the Google Calendar API.
list_free_slots และ book_event เชื่อม Google Calendar API
用 Google 日历 API 实现 list_free_slots 与 book_event。
Anchor Hermes in ICT
Use zoneinfo.ZoneInfo("Asia/Bangkok") so the model never guesses UTC.
ใช้ zoneinfo.ZoneInfo("Asia/Bangkok") เพื่อไม่ให้โมเดลเดา UTC
用 zoneinfo.ZoneInfo("Asia/Bangkok"),让模型不再瞎猜 UTC。
Conflict re-check
Booking must re-query free/busy at the exact moment of insertion — closes the race.
ตอนจองต้อง re-query free/busy ทันที — ปิดช่อง race
下单时再次查 free/busy — 关闭竞争窗口。
🕒 Interactive: the timezone trap
Type a Chiang Mai (ICT) time. Watch where the same moment lands for your foreign clients. Pay attention to London during their DST — that's where most agents hallucinate.
พิมพ์เวลาเชียงใหม่ (ICT) ดูว่าวินาทีเดียวกันตรงกับเวลาใดของลูกค้าต่างประเทศ ระวังลอนดอนช่วง DST — agent หลายตัวสะดุดที่นี่
输入清迈(ICT)时间,看同一时刻在海外客户那边是几点。注意伦敦的夏令时 — 多数代理就在这里出错。
⚠️ DST is a moving target
London + Sydney swap their offset twice a year. Your agent must compute the offset for the booking date — never hard-code it. zoneinfo does this for you.
ลอนดอน + ซิดนีย์เปลี่ยน offset ปีละ 2 ครั้ง agent ต้อง คำนวณ offset ของวันนั้น — ห้ามฮาร์ดโค้ด zoneinfo ทำให้
伦敦和悉尼每年切换两次时区偏移。代理必须按预订日期 计算 偏移,绝不能写死。zoneinfo 会替你处理。
📚 Key concepts
🇬🇧 English
Free/busy scan — freebusy().query() returns busy intervals without exposing private event details.
Timezone math — always pass explicit +07:00 in API calls; use ZoneInfo("Asia/Bangkok") for local-time math.
Conflict re-check — propose → wait for human confirmation → re-check free/busy → book. The re-check closes the race window.
🇹🇭 ไทย
Free/busy scan — freebusy().query() คืนช่วงเวลาที่ไม่ว่าง โดยไม่เปิดรายละเอียดส่วนตัวของอีเวนต์
Timezone math — ส่ง +07:00 ใน API call เสมอ ใช้ ZoneInfo("Asia/Bangkok") สำหรับคำนวณ local-time
Conflict re-check — เสนอ → รอยืนยัน → re-check → จอง การ re-check ปิดช่อง race
🇨🇳 中文
忙闲查询 — freebusy().query() 返回忙时段,不暴露具体事件细节。
时区计算 — API 调用一律带 +07:00;本地时间计算用 ZoneInfo("Asia/Bangkok")。
下单前重查冲突 — 提议 → 等待确认 → 再次查询 free/busy → 下单。这一步关闭竞争窗口。
🧪 Hands-on lab
Add calendar scopes
list_free_slots
book_event with built-in conflict re-check
End-to-end prompt
Paste into the agent REPL with last week's London-client email loaded into your @AI_Handle label:
วางใน REPL ของ agent โดยอีเมลลูกค้าลอนดอนของสัปดาห์ที่แล้วอยู่ใน label @AI_Handle:
把上周伦敦客户的邮件加上 @AI_Handle 标签后,在 agent REPL 里粘贴:
⚠️ Top gotchas
1. Hermes thinks in UTC
Without explicit +07:00 in API calls you'll book at the wrong hour. Anchor everything.
ไม่ส่ง +07:00 ใน API จะจองผิดชั่วโมง ต้อง anchor ทุกที่
API 调用没带 +07:00,订单会落在错误时刻。处处都要锚定。
2. Mid-task token expiry
Wrap build() with a retry-on-401 that triggers load_user_creds() again.
ห่อ build() ด้วย retry ตอน 401 เพื่อเรียก load_user_creds() ใหม่
把 build() 包一层 401 重试,让它重新调 load_user_creds()。
3. Race condition on booking
A human can grab the slot between propose and book. The re-check inside book_event is non-negotiable.
คนอาจคว้า slot ระหว่าง propose กับ book การ re-check ใน book_event ขาดไม่ได้
提议与下单之间有人会抢走时段。book_event 内的二次检查不可省略。
📝 Assessment & homework
✅ Assessment
A Google Calendar event created with correct ICT-to-London conversion and the dummy client invited. Explain why book_event does a second free/busy check.
มี event ใน Google Calendar แปลงเวลา ICT-to-London ถูกต้อง อธิบายว่าทำไม book_event ต้อง re-check
Google 日历里有一个 ICT 转伦敦时间正确、邀请了客户的事件。说明 book_event 为什么要做第二次 free/busy 检查。
🏠 Homework
Propose slots to 2 real clients. Extend list_free_slots with a 30-min travel buffer between events (homestay → studio).
เสนอ slot ให้ลูกค้าจริง 2 ราย ขยาย list_free_slots ให้มี travel buffer 30 นาที (homestay → studio)
给两位真实客户提议时段。给 list_free_slots 加 30 分钟通勤缓冲(民宿 → 工作室)。