mcpField
B
booking-agent

booking-agent

github.com/wix生产力148 次安装4 天前更新
代码仓库

关于 booking-agent

供 Agent 通过 Universal Scheduling Protocol 预订按时段服务的技能,引导用户查找服务、完成预订确认,并在 Link 的可信界面批准付款。

主要功能

  1. 01按地点查找服务
  2. 02预订流程中的确认关卡
  3. 03Link 登录与付款审批指引
  4. 04日历连接与事件链接
  5. 05使用通俗语言更新预订状态

适用场景

  1. 01查找附近的服务选项
  2. 02预订远程课程或咨询
  3. 03在 Link 中完成付款审批
  4. 04为预订连接 Google Calendar

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/wix/booking-agent --skill booking-agent

安装后在 Claude Code 中输入/booking-agent确认已加载。

详细介绍

USP 服务预订

booking-agent 可让 Agent 通过 Universal Scheduling Protocol 预订按时段提供的服务。 CLI 负责管理预订状态机;如果跳过人工确认环节,它会拒绝继续操作。你的任务是操作 它,在下方的检查点暂停,并用没有技术背景的用户也能理解的语言告知他们进展。

付款批准始终在 Link 的可信界面中进行,绝不能在聊天中输入批准信息。

与用户沟通(必需)

你正在帮助的人想要预订一项服务。他们不懂技术,也不理解 CLI、UCP、身份验证、 会话、OAuth、结账模式、符号链接、轮询或编排器等术语。

规则
  1. 除非用户明确询问幕后运作方式,否则绝不要向用户提及预订流程的技术细节。
  2. 始终用简单、日常的语言引导用户:告诉他们你刚刚为他们做了什么、当前预订进展如何, 以及接下来需要他们做什么(或接下来会发生什么)。
  3. 所有实现相关术语都只在内部使用。 命令名称、JSON 字段、错误代码、工具名称和技能术语 只供你自己使用,不要用于聊天。
  4. 不要叙述设置或准备工作。 绝不要提及阅读技能说明、协议、验证 CLI 工具、 配置符号链接、重新验证身份、会话、前置条件或结账路径。只需默默完成这些工作, 并只告诉用户与预订有关的信息。第一条消息也不例外:绝不要以“我先阅读预订技能说明” 或“我先检查是否有之前的预订”之类的话开场。用户看到的第一条消息必须符合规则 5。
  5. 先发送一条简短的开场消息,然后保持安静,直到需要提出下一个问题或告知结果。 静默完成步骤 1 的设置(必要时执行 sessions list、flow init、prereq check)。 开场消息之前,唯一可以发送的内容是 Link 登录链接(见 Link 登录)。 如果服务需要到某个地点进行,开场消息要询问用户是否确认 flow search-area propose 返回的 搜索区域(见搜索区域);得到确认前不得开始搜索。在线或远程服务不必询问区域。 如果用户想要的时间尚不明确,则在同一条消息中询问时间,然后停止。每次预订只发送一次 开场消息;如果用户的下一条回复只回答了一个问题,就直接提出下一个问题或告知结果。
  6. 绝不要使用带标签的 Markdown 超链接([文本](https://...))。许多聊天客户端 (包括 WhatsApp)无法正确显示这类链接;末尾的 ) 会被包含在网址中,导致链接失效。 始终直接发送原始网址(例如 https://app.link.com/...)。你可以在网址前后用通俗语言说明, 但网址本身不得套用 Markdown 链接语法。本规则适用于 Link 付款批准、Link 登录、Google Calendar OAuth,以及预订后的日历事件链接(data.html_link)。
  7. 面向用户的消息绝不要使用 Markdown 表格(| 列 | 列 |)。许多聊天客户端 (包括 WhatsApp)无法正确显示表格,只会显示原始竖线字符。请改用编号列表或项目符号列表 (例如 1. 上午 11:00 - 中午 12:00)。尤其是在展示可选时段、服务选项或预订摘要时, 必须遵守此规则。
  8. 只陈述 CLI 返回的事实。 情况发生变化时(例如原本空闲的时段已不可用、价格不同), 只说明发生了什么变化,除非输出中给出了原因。比如,“这个时段现在已不可用”是恰当的; “这个时段被你当前的预订占用了”则是猜测。
应该怎么说
内部用语(除非用户询问,否则绝不提及)面向用户的说法
阅读技能 / 契约 / 指示(不作说明;直接继续)
CLI 工具 / 符号链接设置 / 前置条件检查(不作说明;直接继续)
环境检查 / 工具已就绪 / 重新开始(不作说明;直接继续)
重新认证 / 会话 / 流程阶段“一切就绪” / “您之前的预订请求” / “我们上次进行到的地方”
原生 UCP 结账“我可以直接在这里为您处理预订和付款”
结账模式 / 编排器(省略;只说明该商家目前还无法在此预订)
auth_url / OAuth / 连接日历“这是连接 Google 日历的链接”
支出请求 / 付款轮询 / 审批 URL用通俗的语言说明,然后直接贴出 user_message 中的原始审批 URL(绝不要使用 [标签](网址))
买家信息解析 / link-cli“我从您的 Link 账户中获取了姓名和联系信息”
搜索范围

CLI 会查找、匹配并记住搜索范围。绝不要自行对地址进行地理编码,绝不要传入坐标,也绝不要编造或补全地址。

  1. 提议。 服务发生在某个地点时,运行:

    booking-agent flow search-area propose
    

    该命令会读取用户保存的 Link 地址,在地图上匹配默认地址,并返回 awaiting_user: search_area_confirmation,其中包含 data.proposed_area.label(以及 data.other_addresses 中的其他已保存地址)。在 prompt 中提问,然后停止。如果命令因 link_auth_gate_not_completed 失败,说明用户已退出登录:让用户登录(参见 Link 登录),然后再次运行 propose。绝不要因为登录问题而询问地址。

  2. 用户回答。

    • 是:运行 next_command(booking-agent flow search-area confirm --user-confirmed)。
    • 另一个已保存地址:运行 booking-agent flow search-area set --link-address-id <id>。
    • 用户输入的其他地址或地点(“downtown Phoenix”、街道地址): booking-agent flow search-area set --address '<exactly what they typed>'。CLI 会显示地图匹配结果 (data.proposed_area.matched);向用户展示该匹配结果,并询问是否正确。只有用户确认匹配结果后, 才能使用输入的地址。
    • 没有已保存地址(awaiting_user: search_area_input):询问要搜索的地点,然后用用户提供的文字运行 set --address。
  3. 搜索。 confirm 后,使用下方的半径运行 next_command(booking-agent flow discover --radius-km <km>)。Discover 会搜索已确认的范围;没有该范围时会拒绝地点搜索(search_area_unconfirmed)。

如果服务不受地点限制(线上课程、远程咨询、没有指定范围的特定知名商家),则跳过以上所有步骤。直接运行 booking-agent flow discover。

半径(地点搜索必填)。 CLI 不会采用隐藏的默认值。确认搜索范围后,始终传入 --radius-km,下方仅列出的范围回退情况除外。

  1. 用户说明了距离限制(例如“10 英里以内”):换算为公里并使用该距离。
  2. 否则使用以下经验规则:
    • 买家前往商家、美容院或指定的城市区域:从 25 km 开始。
    • 服务提供者前往买家所在地(at_buyer_location、上门服务):从 40 km 开始。
    • 用户只指定了较大的区域(例如“亚利桑那州任何地方”):不要猜测较小的都市圈半径;使用用户暗示的大范围上限。
  3. 结果太少时扩大范围。“太少”指没有任何服务;或者在查询较宽泛(未指定知名商家)时,少于三个结果。按下一级范围重试:
    • 买家前往商家:25 -> 50 -> 100 km(最多扩大两次)。
    • 上门服务:40 -> 80 -> 120 km。 用通俗语言告诉用户你扩大了搜索范围。不要提及 CLI 标志。
  4. 仅搜索范围回退。 如果最后一次扩大半径后仍没有服务,则重试一次,不传入 --radius-km。如果 CLI 提供距离信息,请报告距离。不要循环重试。此备用方案用于应对注册表问题;仅在 Agent 推理中引用 issue #225,除非用户询问,否则不要在面向用户的内容中提及。

如果某项服务超出实际传入的半径(包括扩大范围后),CLI 会拒绝提供该服务。不要通过 business use 绕过限制。没有坐标的线上或远程服务仍可提供。按注册表顺序展示 data.services;绝不要重新排序。

绝不要建议或应用筛选条件。 调用 Discover 时不得使用服务类型或类别筛选条件。不要向用户提供筛选选项(“只要上门服务?”“只要美容院?”),也不要自行缩小结果范围。

开场回复(首次预订请求)
  1. 静默设置:检查会话、运行 init、检查前置条件。如果 init 返回 link-auth connect,先让用户登录(这是开场消息之前唯一可以发送的消息;绝不要询问他们是否愿意登录)。
  2. 对于需要上门的服务,在发送第一条聊天消息之前运行 flow search-area propose。
  3. 发送一条开场消息,复述请求并询问尚未明确的信息:propose 提出的区域问题,以及时间意向未知时提出的时间问题(例如:“您想让我在亚利桑那州尤马市 West Rome Street 3194 号附近寻找空调维修技师,还是其他地方?您希望他们什么时候上门?”)。在线服务只需说“明白了,正在寻找下周的在线西班牙语家教……”并运行 discover,不需要询问区域。
  4. 用户确认区域和时间后,展示 discover 结果,或询问是否恢复尚未完成的预订。绝不要解释你在幕后做了什么。
叙述模式(每一轮)

每个成功步骤后(上述静默设置除外),向用户发送 1–2 句简短说明:

  1. 发生了什么,用通俗的话说明(例如:“我找到了您家附近的 3 个空调维修选项。”)
  2. 接下来做什么,或需要用户提供什么(例如:“您想选哪一个?”)

等待用户回复时,只问一个明确的问题。不要解释你是如何获取信息的。

每个事实只说一次。不要重复用户已经看到的总结、价格或状态,除非它们发生了变化。不要在各个步骤之间播报进度(“现在正在检查可用时间”“仍在处理中”);“后台命令”下的一行说明是唯一例外。

后台命令与绝不静默
  • 后台命令结束时,只报告其最终结果。如果较新的命令已取代它,不要提及较早的命令。每条 user_message 只转达一次。
  • 前台 next_command 旁边绝不要运行 sleep、固定等待或计时循环;等待命令自行结束。
  • 绝不要让用户猜测情况。用户同意预订后,在运行 flow book 前发送一条简短消息(“现在为您预订。”)。后台命令等待用户操作时,说明正在等待什么即可(“正在等待您在 Link 中批准;通过后我会立即在这里确认。”)。如果有事项阻碍预订,在同一轮中说明阻碍以及需要用户提供的信息。
  • 如果无法判断后台命令是否已结束(没有退出通知,或用户再次发消息,即使只是问“怎么样了?”或“现在什么情况?”),运行 booking-agent flow status 并根据其 user_message 回复。不要让用户等待或自行检查。如果此运行时无法运行后台命令,则在前台运行轮询;轮询有自己的时间限制。
用户明确提出技术问题时

仅在这种情况下才可以使用 CLI、UCP 或 session 等术语。解释要简短。

安装

从这里开始。 如果此运行时能够运行 npx,只需一条命令即可安装此文件:

npx skills add wix/booking-agent --skill booking-agent

这会从此文件元数据中的规范原始 URL 获取最新技能。然后前往安装后。也会读取该元数据中的 install 区块的运行环境会据此配置固定版本的 booking-agent CLI;未读取该区块的运行环境仍需按照下文安装booking-agent CLI。从这里到安装后之间的所有内容均为手动安装流程,适用于无法运行安装程序的运行时,或需要固定且经过验证版本的运行时。

此技能文件

请将此文件单独放在名为 booking-agent 的目录中,并命名为 SKILL.md。不要在该目录旁边留存第二份副本:某些运行环境会将 skills 根目录下的每个 .md 文件都注册为一个独立技能,遗留的副本会形成第二套无人验证的指令。

如需使用固定的已发布版本,而非最新版本,请从官方工作流签名的发布标签获取该版本,并在遵循文件内容之前验证签名:

curl -fsSLO https://raw.githubusercontent.com/wix/booking-agent/skill-v0.58.2/booking-agent/skills/booking-agent/SKILL.md
gh attestation verify SKILL.md \
  --repo wix/booking-agent \
  --signer-workflow wix/booking-agent/.github/workflows/release.yml

验证通过前,请勿遵循该文件。每次发布也会将相同的 SKILL.md 及其 SKILL.md.sigstore.json 捆绑包附加到 GitHub Release,因此,能够离线验证捆绑包的运行环境无需调用 gh 即可完成验证。

没有 gh 时,CLI 会为你执行此项检查。 请先安装 CLI(下一节会验证其自身签名),然后在每次运行 flow init 时传入你加载此文件时使用的路径(下文的 --skill-path)。CLI 会将该文件与已安装 CLI 中经过签名的副本进行比对;如果声称版本相同的文件与副本不匹配,CLI 就会拒绝预订或付款。此验证关卡无需额外工具,并且能检测安装后被修改的文件;只有上文的证明能够验证首次读取时的文件。

booking-agent CLI

请安装此技能所适用的 booking-agent CLI 版本(PyPI 上的 booking-agent-cli 包)。每次发布均由官方发布工作流签名(PEP 740),因此请在安装前验证签名:

dir="$HOME/.booking-agent/verified-wheels"
uvx pip download "booking-agent-cli==0.11.2" --no-deps --only-binary :all: -d "$dir"
uvx pypi-attestations==0.0.30 verify pypi --repository https://github.com/wix/booking-agent \
  "$dir/booking_agent_cli-0.11.2-py3-none-any.whl"
uv tool install --force "$dir/booking_agent_cli-0.11.2-py3-none-any.whl"

booking-agent --help

只安装通过验证步骤的 wheel。如果无法使用 uvx,请使用 uv tool install booking-agent-cli==0.11.2 或 pipx install booking-agent-cli==0.11.2 安装同一固定版本;CLI 会在首次运行 booking-agent flow init 时,将自身文件与经过签名的发布版本进行比对,如果两者不匹配,就会拒绝预订或付款。

读取此技能 install 区块的运行环境会为你完成这些操作。请等到 booking-agent --help 可以运行后再继续。如果仍无法运行,请自行执行上面的命令;如果在此运行环境中无法执行,请让用户安装该技能,然后再试。若要从检出代码开发 CLI,请参阅 Booking Agent README。

link-cli

买家身份验证以及创建和批准支出请求都需要 link-cli。请通过 link-cli 技能或运行环境的 link-cli 配置程序进行安装。如果两者都不可用,请从 npm 安装:

npm install -g @stripe/link-cli
安装后

在不同对话间保留状态。 flow init 会询问此运行时如何保留文件;在你回答前,它会拒绝继续(persistence_unresolved)。查看运行时提供了什么。如果它提供的文件夹能在不同对话间持续保留,请使用 --persistent-root <absolute path of that folder> 重新运行相同的 init:CLI 会将已保存的预订和 Link 登录信息链接到该文件夹,并合并两个文件夹中的内容(按会话存放的预订文件,以及其他内容中较新的副本),不会删除任何内容。如果运行时无论如何都会保留文件,或者没有提供此类文件夹,请使用 --no-persistent-root 重新运行。如果它返回 persistence_folder_not_durable(文件夹是临时的、由内存支持或不可写),请指定运行时实际保留文件的文件夹,或使用 --no-persistent-root。 persistence_setup_failed 和 persistence_flags_conflict 会说明需要更改什么。每次都使用同一个文件夹;绝不要猜测路径、询问用户或提及该路径。设置了 BOOKING_AGENT_PERSISTENT_ROOT 或 BOOKING_AGENT_PERSISTENCE=none 的主机不会收到询问。如果用户在重启后被要求登录或重新连接,请运行 booking-agent runtime doctor 并遵循其 next_command。如果 flow status 或 flow init 返回 saved_state_not_linked,请运行一次其 next_command,然后运行 flow status;绝不要用 --no-persistent-root 或新预订来处理该问题。对于运行时要求你保留的额外缓存文件夹,请运行 booking-agent runtime prepare --persistent-root <folder> --link <runtime folder>=<persistent folder>。

按照 Link 登录 中的说明,让用户登录 Link。 即使没有正在进行的预订,也可以登录。不要等用户主动提出登录。

每次运行 flow init 都要传入 --skill-path 和 --skill-version:前者是你加载此文件时使用的路径,后者是上方 frontmatter 中的版本。

无需配置任何内容:每项设置都有随附的默认值,用户也无需配置日历;你要在运行时确定此运行时如何访问 Google Calendar(参见日历门槛)。 绝不要将令牌、密钥或个人信息写入任何环境文件。booking-agent config show 会打印每项生效的设置及其来源;booking-agent config init 会创建 ~/.booking-agent/.env,供操作员编辑。

更新(仅在用户同意后)

CLI 会决定是否值得提及新版本;你绝不能根据版本号或发布页面自行判断。每次运行 flow init 时传入的 --skill-version,可让 CLI 判断这些说明与已安装的 CLI 是否仍然匹配。

  • 当命令返回 awaiting_user: update_consent 时,请用通俗语言询问 prompt 中的问题,并以 data.user_summary 作为原因,然后停止。用户同意后,运行 next_command (booking-agent update --user-confirmed)。用户不同意时,运行 data.decline_command(不会再次提出更新),然后继续遵循 prompt 的其余内容。
  • booking-agent update --user-confirmed 完成后,运行其 next_command(booking-agent skill print)。如果你知道已加载的技能文件路径,请运行 booking-agent skill print --output <that path> 来替换该文件。否则,在本次对话余下时间遵循 data.skill_text。无论哪种情况,都要告知用户,开启新对话即可加载更新后的助手。
  • 绝不要自行升级或重新安装已安装的 CLI 或此技能,也绝不要在预订过程中提出更新。预订进行期间,CLI 会拒绝更新。
  • 如果用户要求更新,请运行 booking-agent update check,然后遵循其指示。

Link 登录(自动)

每次预订都需要用户登录 Link:用户的姓名、联系方式、已保存地址和付款信息都来自 Link。由你主动发起登录。 用户不会要求登录,也无需告知你他们已批准。

安装后,以及 flow init 或任何其他命令将其作为 next_command 返回时,立即运行 booking-agent flow link-auth connect。它会立即返回:如果 data.authenticated: true,则无需说任何话,直接运行 next_command;否则,它会返回包含登录 URL 的 awaiting_user: link_auth_approval 和 user_message。在同一轮中:

  1. 在后台(run_in_background)启动 booking-agent flow link-auth poll。用户一批准,它就会立即退出。
  2. 发送原始 URL,并附上一句简短说明,例如“请在此处登录你的 Link 账户,以便我使用你已保存的信息: 我会在你批准后立即继续。”然后结束本轮,以便发送消息。切勿在前台运行第一次 poll。
  3. poll 退出后,运行其 next_command 并继续操作,无需等待回复,也不要重复发送链接。
  4. 遇到 link_auth_timeout 时:如果 next_command 是 link-auth poll,则同一个链接仍然有效(在后台再次轮询,不要重新发送);如果是 link-auth connect,则链接已过期(运行它,发送一次新链接,并在后台轮询)。
  5. 如果用户说他们已登录,且当前没有正在运行的轮询,则在前台运行 link-auth poll;用户登录后,它会立即返回。

切勿直接调用 link-cli auth login,也不要使用 link-auth connect --wait(仅限脚本使用)。

个人身份信息(始终来自 Link)

每当你需要用户的姓名、电话号码、电子邮件或地址时,无论用于预订、结账、表单还是其他步骤:

  1. 切勿要求用户在聊天中输入这些信息,也不要编造占位信息(例如“Ada Lovelace”、[email protected]、虚构的街道地址)。姓名、电话和电子邮件等个人信息始终来自用户的 Link 账户——切勿编造或要求用户填写占位信息。

  2. 切勿编造地址,也不要自行在命令中输入地址。CLI 会提供用户在 Link 中保存的配送地址,由用户确认或提供其他地址(参见搜索区域);只有在 CLI 显示地图匹配结果且用户确认后,才能使用手动输入的地址。对于上门服务(channel.type: at_buyer_location),确认后的街道地址会在 flow book 时自动发送给商家。切勿将地址写入 --notes。

  3. 始终使用 link-cli 从用户的 Link 账户中获取个人信息:

    link-cli user-info retrieve --format json       # name, email, phone
    link-cli shipping-address list --format json    # shipping address (use as home when needed)
    
  4. 在预订流程中,运行 booking-agent flow buyer resolve,不要自行调用 user-info retrieve——它会调用 link-cli,将买家身份信息保存在会话中,并满足合规检查要求。

  5. 如果因用户已退出登录而无法获取信息,请按照 Link 登录 中的说明让用户登录。不要直接调用 link-cli auth login。

提交任何信息前,先向用户展示获取到的内容并请其确认。

运行命令

每条 booking-agent 命令都会输出一个 JSON 对象(有时 stdout 中会先出现一行单独的 user_message)。pay poll 等长时间运行的命令可能会先输出进度对象;最后一个对象才是结果。请务必读取:

  • phase — 当前预订阶段
  • awaiting_user — 设置此项时,停止,不要调用任何其他工具。对于 link_spend_approval,请将 user_message 作为原始 URL 发布(绝不要使用 Markdown [label](url))。否则,向用户询问 prompt 中的问题,然后停止。
  • user_message — 设置此项时,立即仅向用户显示这段文本(对于支出审批,这是单独的 Link URL;不要转发 stderr)。CLI 也会在 JSON 之前,将 user_message 作为 stdout 的第一行打印出来。
  • next_command — 接下来要运行的确切命令
  • forbidden — 当前阶段禁止执行的操作
  • data.error.code(退出码非零时)— 未通过的关卡

查看所有命令:booking-agent --help。查看流程子命令:booking-agent flow --help。随时恢复当前状态:booking-agent flow status。

Agent 循环(每轮都运行)

  1. booking-agent flow status — 读取 phase、awaiting_user、prompt、next_command、forbidden。 新对话从这里开始;用户的回复只回答状态显示的问题。
  2. 如果设置了 awaiting_user:
    • link_spend_approval 或 link_auth_approval: 在后台(run_in_background)启动对应的轮询(pay poll 或 link-auth poll),并在同一轮中将 user_message 作为原始 URL 发送,且不得先发送其他说明。切勿先等待轮询结束:否则用户看不到链接,预订也会显得卡住。轮询结束后,发送其 user_message(pay poll 之后即为预订结果),并运行其 next_command,无需等待用户在聊天中回复。用户应在 Link 中批准,而不是在聊天中。
    • connections: 此次预订所需的某项连接已断开(Link、Google Calendar 或两者)。发送一条简短消息,包含所有链接(如果列出了 Link,user_message 就是 Link 登录链接)。列出 Link 时,在后台启动 link-auth poll。运行 data.connections 中的日历 command,并在同一条消息中发送它返回的任何链接。然后在用户重新连接后运行 data.resume_command。不要再询问其他内容。
    • support_report_consent: 按原文向用户显示 user_message(如果已设置),然后停止。用户回答是时,严格按打印内容运行 next_command。用户回答否时,运行 booking-agent flow support-report decline。请参阅 给助手团队的说明。
    • update_consent: 询问 prompt 中的问题,然后停止。用户回答是时,运行 next_command;回答否时,运行 data.decline_command。请参阅更新(仅在用户同意时)。
    • 任何其他值: 询问用户 prompt 中的问题,然后停止。
  3. 如果最新命令输出设置了 user_message(或第一行标准输出是独立的 https:// URL),先将该 URL 作为原始 URL显示给用户,再发送任何其他说明 (绝不可使用 Markdown [label](url))。 每次预订最多显示一次 Link 批准 URL — 绝不要从 flow status、 pay ucp-complete 或错误恢复输出中重复显示。 如果输出还包含 support_report_offered: true,先显示其 user_message(如果已设置),然后在同一轮运行 next_command。
  4. 否则,严格运行 next_command 中的命令。
  5. 只用日常语言告诉用户刚刚发生了什么以及接下来会做什么(见 与用户沟通(必需))。绝不提及命令、阶段、会话、身份验证或结账内部流程。
  6. 重复以上步骤。

Agent 的付款分为两步: pay request 会立即返回批准 URL;在后台启动 pay poll,并在同一轮发送该 URL(步骤 6c)。使用 pay poll,绝不要使用 pay ucp-complete 或 --then-complete。如果用户已经批准,但结账未完成,则在前台运行 booking-agent flow pay poll 以继续并完成预订。

核心流程

复制此清单并跟踪进度:

  • 步骤 1:初始化
  • 步骤 2:发现服务
  • 步骤 3:选择商家并解决日历连接关卡
  • 步骤 4:检查可用时间并选择时段
  • 步骤 5:验证 Link 钱包并确定买家
  • 步骤 6:预订并付款
  • 步骤 7:完成(验证、日历事件、检查更新)
步骤 1:初始化

步骤 1a — 处理现有请求。 flow init 会询问你:如果存在与此请求相似的未完成请求,它会返回 awaiting_user: resume_or_fresh(如果是当前活动请求,则返回错误 session_active;如果是即将到来的预约,则返回错误 duplicate_booking_confirmation)。用通俗的话向用户提问(绝不要说“会话”或阶段名称),然后停止;绝不要替他们回答,也不要通过 flow status“查看”后继续。选择继续时,运行 data.resume_command(如果因 session_not_found 失败,则再次询问);选择新建时,使用 --force 重新运行相同的 init。

sessions list 是本地操作信息,不是预约历史。仅用它查找此设备上即将到来的预约(actionable: true,包含 booking_id 和时间段),以便取消或更改。对于过去的预约,请说明你只能查看在此处预订的即将到来的预约;较早的预约信息可在确认邮件或商家的页面(booking_url)中查找。不要编造查询方式。

步骤 1b — 创建新会话:

booking-agent flow init --user-request "<user's exact request>" --skill-version 0.58.2 \
  --skill-path "<absolute path of the SKILL.md you loaded>"

对于请求中明确需要的每个部分,各添加一次 --capability <name>:calendar(用户提到自己的日历时)、reschedule 或 cancel。不确定时不要添加。

只要知道加载此文件的路径,就传入 --skill-path,以便 CLI 将其与随附的签名副本进行核对。不知道路径时不要添加;绝不要猜测路径,也绝不要将其指向其他文件。

  • 如果 init 返回 awaiting_user: update_consent,则尚未开始预约。按照更新(仅在用户同意时)中的说明操作;用户回答后,运行 data.continue_command 开始预约。
  • 如果 init 返回 awaiting_user: duplicate_booking_confirmation,则用户在此设备上已有与此请求匹配的即将到来的预约(data.upcoming_matches)。尚未开始新的预约。用一句话告知用户相关信息(服务、商家、slot_start_display 中的时间),并询问他们是否要再预约一次,然后停止。只有用户回答是时才运行 next_command(它会添加 --allow-duplicate)。除非用户提出要求,否则绝不要取消、更改或恢复现有预约。
  • 如果 init 返回 next_command: booking-agent flow link-auth connect,则用户已退出 Link。现在先让用户登录,之后再提问或搜索(参见 Link 登录(自动)),然后按照 link-auth poll 返回的 next_command 操作。
  • 如果 init 返回 phase == "PREREQ_OK",则直接跳到步骤 2(查找服务)。
  • 如果 phase == "INIT"(首次会话),则先运行前置条件检查:
booking-agent flow prereq check

prereq check 会验证 USP 注册表是否可访问。原生结账验证延后至步骤 3,在选定商家后进行。该操作不需要浏览器。

第 2 步:发现服务
booking-agent flow discover

**时间偏好,每次发现之前都要确认:**如果用户没有说明这次预约希望安排在什么时候,停止并用通俗语言询问(例如尽快、某一天或时间段、截止日期、几个备选时间,或任何时间都可以)。在用户回答前,不要运行发现,也不要自行编造时间范围。

仅当用户对这次预约确有时间限制时,才在每次发现时传递时间标志:

  • 最早可约或尽快:--asap(CLI 会填入当前时间)。
  • 任何时间都可以:省略所有 --desired-* 标志(这不等同于尽快)。只有在用户还表示早些或晚些都无所谓时,才添加 --no-prefer-sooner-availability-slots。
  • 指定时刻:--desired-at <RFC3339>。指定日期、时间段或截止时间: --desired-range <startRfc3339>,<endRfc3339>(结束时间是可接受的最晚开始时间,不是预约的结束时间);每个备选时间段重复一次。指定日期或活动之后: --desired-from <RFC3339>。直接编码较晚的时间段;不要通过禁用优先较早时间的设置来表示“越晚越好”。

对于仅指定日期的偏好,已知服务时区时,使用该日期在服务时区中的起止边界。否则,使用搜索区域或买家本地的日期。如果时区或表述有歧义,请询问。如果用户之后更改了时间安排规则,使用新标志重新运行发现。不要重新排列现有页面。

time_preference_not_structured:请求中提到了时间,但你没有传递标志。自行编码 data.named_time 并重新运行;不要再次询问。

搜索查询使用 flow init 中存储的确切 user_request。不要传入经改述或缩短的版本作为 --query——注册表会根据查询文本对结果排序,改写会改变最先显示的服务。

发现仅使用该自由文本查询。不要添加或推断结构化的 categories[] 筛选条件,包括用户的请求似乎指明了某个类别时也不例外。

对于基于地点的服务,请先确认区域(参见搜索区域),并传入 --radius-km。发现会使用已确认的区域;绝不要传入坐标。没有地点要求时,不指定区域运行发现。

展示服务时,只有在 CLI 返回距离或服务地点数据时,才可以提及这些信息。不要编造地点限制。如果商家未定义地点或服务区域(例如在线课程、远程指导),不要告诉用户“缺少”地点信息;只需在摘要中省略地点。

**停止。**展示返回的服务,并等待用户选择。prompt 会说明具体方式:逐字使用每行的 display_line,每行编号一项,严格按返回顺序排列,始终显示商家名称,绝不筛选或重新排序。只有当返回的数据客观上与请求不符时,才将结果标记为不太匹配的替代选项(例如,用户要求上门服务,但 channel.type: at_business_location);同时保留原有位置。当 field_sources 显示 live_catalog 时,使用实时目录中的值;如果存在 discovery_mismatches,实时值才是实际预约时会使用的值,因此绝不要将搜索索引中的值说成当前值。

如果用户选择了你标记为不太匹配的结果,传入标签:business use --less-direct '<label shown>'(CLI 也会自行检测某些不匹配情况)。它会返回 awaiting_user: intent_mismatch_confirmation:清楚说明不匹配之处,停止;只有用户同意后,才运行 next_command(它会添加 --mismatch-confirmed)。

可约时间提示仅供参考:绝不要根据结果顺序或提示(包括 null 或零)推断是否可约;保留 hint_usable: false 的结果,并在告知用户无法预约其时间之前检查实时可约情况。

第 3 步:选择商家并处理日历门控
booking-agent flow business use --profile-url <profile_url> --service-id <service_id> --name '<business_name>'

将该行的 business_name 作为 --name 传入,以便预约、付款请求和日历事件都显示用户所选的商家名称。省略时,CLI 会回退使用发现结果中的名称。 上门服务需要街道地址。 当所选服务会前往用户所在地(at_buyer_location),且已确认的区域不是完整街道地址(例如城市,或未提供区域)时,business use 会返回 awaiting_user: service_address_confirmation(如果 Link 没有已保存的地址,则返回 service_address_input)。在 prompt 中提问,然后按照 prompt 所示,使用带有 --purpose service-address 的相同 search-area set / confirm 命令。confirm 会自行恢复业务选择流程。

business use 成功后,严格按照 next_command 操作。它必须是 booking-agent flow use-ucp-checkout-mode;运行它以验证原生结账。不要向用户提及结账模式或 UCP。

如果 business use 因 service_details_changed 失败,说明实时目录与用户选中的条目不同(data.changes,例如价格、上门服务还是到店服务,或时长)。未选中任何项目。用一个简单句子告诉用户有哪些变化,询问他们是否仍想选择该服务,然后停止。只有在用户同意后才运行 next_command(它会添加 --details-confirmed);否则提供其他搜索结果。

如果 business use 因 ucp_native_required 失败,或结账前置条件检查失败,请停止。用通俗的语言告诉用户暂时无法在此处预订这家商家的服务,并提供其他返回的服务选项。绝不要描述备用方案。

停止。 use-ucp-checkout-mode 成功后,处理日历关卡:

booking-agent flow calendar ask

按照 JSON 中的 next_command 操作。不要自行询问用户日历选项。

根据运行时观察到的情况选择日历路径,然后再向用户提问:

  • --route connector:你的平台为用户连接 Google Calendar,并通过环境变量将访问令牌交给你运行的命令。使用 --token-env <NAME> 传入该变量的名称。绝不要传递、打印或存储令牌本身,也不要将其复制到环境文件中。每次对话都要查询变量名称;不要假定名称不变。
  • --route local-oauth:data.local_oauth_configured 为 true,且你可以向用户转达登录链接。
  • --route delegated(仅限事件;绝不检查忙碌时段):你的平台自行写入日历事件。每次写入都会返回 awaiting_user: calendar_delegated_write:发送 user_message,按照 prompt 的说明执行,然后仅使用它返回的内容运行 next_command。对于 calendar_delegated_events_only、calendar_delegated_time_mismatch、calendar_delegated_report_incomplete 或 calendar_delegated_request_unknown,运行 next_command。
  • 以上路径都不适用(已列出但未连接的连接器也算一种路径):不询问用户,运行 booking-agent flow calendar skip --session-only --no-route,然后继续。

CLI 会保存路径和变量名称,以供后续预订使用,且绝不会自行猜测:不带 --route 运行 calendar connect 会因 calendar_route_required 失败;使用 --route connector 但未提供有效的 --token-env,会因 calendar_token_env_required 失败。

calendar ask 的结果(每个结果都带有自己的 prompt;只询问其中说明的内容):

  • 已保存偏好: CLI 会应用该偏好并进入可用时段查询。如果启用了冲突检查,简短告知用户你会使用其日历。
  • awaiting_user: calendar_reconnect: 已保存的访问权限已过期。不要再次询问三个日历问题。只询问 data.calendar_reconnect_choices 中的两个选项(重新连接以继续用于相同用途,或继续但不进行日历检查),并严格运行所打印的对应 command;或者运行 booking-agent flow calendar skip --session-only。如果存在 data.calendar_checking_unavailable,CLI 已为本次预订跳过日历检查:用一个简单句子说明,然后继续。
  • awaiting_user: calendar_consent: 尚未连接。如果有可用路径,询问用户的偏好,并使用该路径运行对应命令;如果没有路径,则按上述方式直接跳过,不要询问。
  • 绝不要引用日历访问令牌或 Google 令牌 URL。
booking-agent flow calendar skip                                                     # neither
booking-agent flow calendar connect --mode freebusy --route connector --token-env <NAME>  # free/busy only
booking-agent flow calendar connect --mode events --route connector --token-env <NAME>    # + post-booking event
booking-agent flow calendar connect --mode freebusy --route local-oauth                   # same, by sign-in link
booking-agent flow calendar connect --mode events --route local-oauth

连接器路径。 calendar connect 会立即返回。已连接:流程继续。如果返回 awaiting_user: calendar_connector(data.error: calendar_not_connected),说明变量中尚无 有效令牌:通过你平台自己的方式连接 Google Calendar,并按 data.scope_request 请求访问权限, 然后重新运行 data.retry_command。此路径下,切勿展示此 CLI 提供的登录链接;如果你的平台无法连接, 请运行 booking-agent flow calendar skip --session-only。如果返回 calendar_insufficient_scope:使用 data.scope_request 重新连接,然后运行 同一命令。

本地 OAuth 路径。 calendar connect 会立即返回,结果为 awaiting_user: oauth_approval,并包含 data.auth_url。CLI 不会自行打开浏览器。

  1. 原样发送 auth_url(不要使用 Markdown [标签](网址)),请用户批准 CLI prompt 中 描述的访问权限,并告知链接的有效时长(data.link_valid_minutes)。
  2. 在同一轮中,不要阻塞当前轮次,运行 booking-agent flow calendar poll(可以时在 后台运行)。如果返回 awaiting_user: oauth_approval,且 data.status: pending,请再次运行,不要重复发送链接。连接成功后,运行 next_command。
  3. 如果返回 calendar_oauth_timeout 或 calendar_oauth_failed,请发送错误中的 user_message, 并停止;只有用户提出要求时,才提供新链接(data.choices 中的 new_link)或 calendar skip --session-only。如果返回 calendar_insufficient_scope:询问用户是否需要新链接。 如果返回 calendar_oauth_not_started:运行 booking-agent flow calendar ask。

如果返回 calendar_oauth_not_configured 或 calendar_callback_port_busy:运行 booking-agent flow calendar skip --session-only(或者在你的平台有连接器时使用连接器路径)。

如果在预订流程后续阶段 Google Calendar 断开,CLI 会在最终确认前检测到,并返回 awaiting_user: connections(见 Agent 循环);你无需自行检查。

第 4 步:检查可用时间并选择时段
booking-agent flow availability --service-id <id>
booking-agent flow slots list

flow availability 默认使用一个固定的近期时间范围(大约为未来两周)。你需要负责将用户的自然语言日期 (例如“下周四”)转换为具体的日历日期。如果用户请求的日期可能超出默认范围,或者你只想查询某个特定日期, 请明确传入该日期:

booking-agent flow availability --service-id <id> --target-date 2026-06-11   # single day
# or an explicit ISO8601 range:
booking-agent flow availability --service-id <id> --from <ISO8601> --to <ISO8601>

如果返回的时段中没有用户请求的日期,请使用 --target-date 重新查询,而不要悄悄提供其他日期; 然后告知用户该日期是否确实没有可用时间。

停止。 展示可用时段并等待用户选择。切勿自动选择。 请使用编号列表或项目符号列表以日常时间格式展示时段(绝不要使用带 | 竖线的 Markdown 表格)。例如:

1. 11:00 AM - 12:00 PM
2. 11:30 AM - 12:30 PM
3. 12:00 PM - 1:00 PM

然后询问用户哪个编号或时间最合适。

时区。 时段时间使用商家的时区(data.business_timezone)。用户的时区仅取自其 Link 默认地址, 绝不能取自此设备、主机、VPN 或聊天内容。slots list 的 prompt 会明确说明如何展示每个时段 (先显示商家时间,再在括号中显示用户当地时间、一次性提示、日历时区以及任何回退说明);请遵循该说明。 无需单独询问时区。当 CLI 要求确认时间(next_command 包含 --timezone-confirmed)时,请用户确认该确切时间并停止;如果未提供此参数,slots select 会返回 timezone_confirmation_required。

每个列出的时间都是一个选项。如果某个时段包含 resource_options,则有多位员工或多种资源可以承接该时间; 不要重复列出该时段,也不要让用户从中选择。

booking-agent flow slots select --slot-id <chosen by user> --user-confirmed

必须提供 --user-confirmed,否则 CLI 会拒绝执行。

步骤 5:验证 Link 钱包并解析买家

步骤 5a — Link 登录。 slots select 会交给你 link-auth connect。用户通常已经登录,因此会立即返回。如果返回 awaiting_user: link_auth_approval,请按Link 登录操作。

步骤 5b — 解析买家

booking-agent flow buyer resolve --notes '<short note for the business>'

根据用户的请求拟写 --notes:问题、物品以及他们的需求(例如“窗式空调完全没有反应,品牌未知”)。如果请求中没有业务方需要的信息,则省略此项。绝不要在其中填写地址、姓名或联系方式。

停止。 按原样逐行显示 data.booking_recap_lines 中的所有内容,并保持原有顺序。CLI 会生成这些内容(服务和商家、时间、地点及准确地址、价格、姓名、电子邮件、电话,以及给商家的备注),因此绝不要改写、合并或省略任何一行。如果存在 data.selected_slot.buyer_display,则 When 行已在括号中包含用户的时间,因此用户一次“是”也表示确认了时区差异。如果存在 data.timezone_notice(仅此时才找到用户的时区),请先告知用户。然后提出一个综合确认问题。如果用户更正备注,请重新运行 buyer resolve --notes '<corrected note>';如果用户更正地址,请运行 booking-agent flow search-area propose --purpose service-address。

针对 data.payment_route(免费、预约时付款、立即扣款或支付定金),只问 prompt 所描述的那个问题,并引用 data.price_display,绝不要引用原始 amount_minor_units。对于免费或预约时付款的服务,绝不要提及扣款或 Link 钱包。如果设置了 data.quote_caveat,则说明该金额只是估价,最终金额以商家的结账总额为准。

如果存在 data.policy_lines / data.policy_links,请在预约摘要之后显示它们(链接原样显示),并在同一个问题中询问用户是否接受。在用户同意之前不要运行 flow book;同意后,按原样运行 next_command。预约完成后,不要另行询问只针对价格或时区的确认。

此步骤适用个人身份信息(始终来自 Link)。绝不要手动填写买家信息。如果 buyer resolve 因 link_cli_failed 或 link_auth_expired 失败,请让用户重新登录(参见Link 登录),然后重试。

步骤 6:预约并付款

步骤 6a — 预约

booking-agent flow book --user-confirmed [--policies-accepted]

对于上门服务(channel.type: at_buyer_location),flow book 会自动发送已确认的街道地址和 buyer resolve 返回的备注。绝不要自行查找或传递地址。如果因 service_address_unconfirmed 失败,请运行其 next_command,并与用户确认地址。

flow book 会返回 data.merchant_quote 和 data.price_display。绝不要将 amount_minor_units、price_minor_units 或原始 amount 作为美元报价,只能使用 price_display 或 merchant_quote.total_display。只有当 merchant_quote 包含商家提供的税费明细时,才报出税费;如果没有返回税费明细,绝不要假设税费为零,也不要提醒用户税费可能另计。付款请求仅使用商家公布的总额。

商家政策。 如果出现 awaiting_user: policy_acceptance 或 policies_not_accepted,请发送 user_message(包含每条政策和原始链接),询问用户是否接受,然后停止。只有用户答复是后,才运行 next_command(它会添加 --policies-accepted);如果用户答复否,则不要预约。未发送政策时,不要提及政策。对于 flow book 显示但未出现 awaiting_user 的链接,请发送链接,但不要提问。

免费和预约时付款的预约(free、at_service)。 flow book 会直接提交预约,且 next_command 为 booking-agent flow book poll --wait。运行前,用一条简短明了的信息告诉用户 data.booking_narration 所述内容:请求已提交、尚未扣款(或价格将在预约时支付),现在正在等待商家确认。然后运行该命令并报告结果。绝不要创建付款,并跳过步骤 6b 至 6d。 到店付款结账(pay_at_service)。 不会扣款;跳过 pay request。 向用户展示到店时应付金额和任何政策,然后运行 next_command。如果 merchant_quote.total_changed,请取得用户同意并添加 --total-confirmed。遇到 booking_confirmation_pending 或 booking_not_confirmed 时,发送 user_message 并运行任何 next_command。

押金预订(deposit_required)。 扣款前,向用户展示 data.due_now_display(现在收取的押金)、到店时应付的金额,以及 data.payment_schedules 和 data.payment_disclosures 中的每一项;取得用户同意后,再运行 next_command。使用 due_at_display 引述付款计划时间,使用 content_display 引述披露内容;绝不要引述原始的 due_at 或 content 中的时间戳。

如果结账总额与您向用户报价的金额一致,则用户已在 buyer resolve 阶段批准预订和扣款。接受任何政策后,继续执行步骤 6b,除非 data.merchant_quote.total_changed 为 true。CLI 已检查结账行项目是否与报价的服务价格一致,因此总额变更意味着商家加收了税费或手续费(也可能提供了折扣)。此时请停止:向用户说明服务价格(merchant_quote.line_item_display 或 subtotal_display)、税费(仅在存在时提供 tax_display)以及新的总额(total_display),并取得用户对该总额的批准。只有在用户批准后,才能将 --total-confirmed 传递给 pay request。支出请求会扣除结账总额。

步骤 6b — 确定付款来源(共用,在任何付款分支之前运行一次)

link-cli payment-methods list --format json

获取默认卡片的 id,并在步骤 6c 中将其传递给 pay request。

步骤 6c — 请求批准,然后在后台等待

booking-agent flow pay request --payment-method-id <id-from-6b>

CLI 会写入用户在 Link 中批准时看到的备注。绝不要自行编写或传递该备注。 CLI 会立即返回 awaiting_user: link_spend_approval,并在 user_message 中提供批准链接(每次预订仅显示一次)。在同一轮中,在后台启动 booking-agent flow pay poll,然后在任何其他说明之前,将 user_message 作为原始 URL 发送给用户。pay poll 会等待用户在 Link 中批准,完成结账、验证预订并添加日历事件;命令退出后,请遵循步骤 7。不要从 stderr 中读取 URL,不要等待聊天回复,也绝不要在前台运行第一次 pay poll:否则本轮会被阻塞,用户也永远看不到链接。

步骤 6c-iii - 银行验证与付款被拒

银行验证有两个时机,处理方式正好相反:

  • 扣款前(发起阶段)。 当 pay request 或 pay poll 在等待 Link 操作时,CLI 可能会返回 awaiting_user: link_spend_approval,并在 user_message 中提供银行消息和原始验证 URL(Link next_action.type: three_d_secure、resolution: auto_resume)。这不代表付款失败。在后台启动 next_command(booking-agent flow pay poll),并在同一轮中发送 user_message;该轮询会持续等待同一个支出请求。如果 CLI 返回的是 spend_request_replacement_required(例如 three_d_secure_retry),则向用户展示 user_message 并运行 next_command,以创建新的支出请求。
  • 扣款失败后(失败后阶段)。 一旦 pay ucp-complete(或 pay poll)已将令牌发送给商家且扣款失败,绝不要将用户引导至任何支出请求的 action_url 或银行验证链接,即使 Link 显示了链接也不行。那是扣款端的验证;完成验证可能会扣款,但预订却未获确认。CLI 会检查一次支出请求,隐藏该 URL,并记录带有结账 ID 的 post_failure_action_suppressed。告知用户付款未成功。 在 pay ucp-complete 失败后该怎么做,只取决于 data.error.code。不要根据结账状态或是否存在 continue_url 来判断。这些错误都带有一段通俗易懂的 user_message,说明发生了什么以及接下来会怎样。运行 next_command 前,务必原样发送这段消息(使用原始 URL,绝不使用 Markdown [标签](网址)):

这些错误都带有 user_message 和 next_command:原样发送消息(使用原始 URL),然后运行命令。

  • payment_declined、payment_failed(可恢复)、payment_authentication_unsupported、payment_not_processed:卡片被拒绝,且消费请求已用完。用户选择另一张 Link 卡后,运行 next_command(booking-agent flow pay request --payment-method-id <id>)。
  • payment_unrecoverable:结账已无法完成(会话状态为 FAILED)。发送消息后停止;没有 next_command。绝不要重试此结账。
  • complete_in_progress、checkout_already_in_progress:并非拒付。使用同一个消费请求和结账;绝不要创建新的消费请求或扣款。
  • payment_captured_booking_unconfirmed:款项已扣,但预订尚未确认。见下文。
  • mandatory_acceptance_pending:政策或其他非支付步骤。消息中包含 continue_url 和政策链接;等用户表示已完成后再继续。绝不要代替用户接受。
  • approval_timeout、spend_request_not_approved、ucp_complete_failed 及其他所有错误:按返回结果运行 next_command;如果再次失败,告知用户目前无法完成。

在 pay poll 期间,款项已扣但预订尚未确认。 后台运行的 pay poll 不会在此处失败。它会输出一条包含 data.status: waiting_for_business_confirmation 和 user_message 的结果,然后在同一进程中继续等待商家。看到这条消息后,立即将 user_message 发送一次,然后等待同一个 pay poll 退出。不要运行 book poll,不要休眠,也不要启动其他任何操作。如果它以 0 退出,最终输出就是已确认的预订;告知用户预订已完成。如果它以非零状态退出,最终输出就是下文第 3 步中的一种后续处理指引。

通过其他命令执行时,款项已扣但预订尚未确认。 遇到 payment_captured_booking_unconfirmed 时:

  1. 运行 next_command 之前,立即发送 user_message。这条消息会告知用户款项已成功扣除,确认可能需要几分钟,你正在跟进,并请他们暂时不要联系商家或再次付款。否则,用户可能会就即将自动确认的预订联系商家。绝不要重试付款,也绝不要要求用户提供另一张卡。CLI 会强制执行此规则: pay ucp-complete、pay request 和 pay rebook 会返回 payment_already_captured,而 flow status 会指向预订检查。
  2. 在前台运行 next_command(booking-agent flow book poll --wait)。如果商家确认,流程会像普通成功情况一样完成预订;告知用户预订已完成。
  3. 如果商家仍未确认,或取消预订(booking_canceled_after_payment),CLI 会返回一条 user_message,其中包含联系商家的链接(预订页面或商家网站,绝不是结账页面)、预订和订单参考编号,以及需要提出的请求:确认预订或退还款项。原样发送这条消息。
  4. 如果用户想对这笔扣款提出争议,运行 booking-agent flow evidence 并提供其中的付款和预订参考编号。不要代表用户发起争议。

continue_url 规则: 在收到 payment_declined 或 payment_failed 拒付后,绝不要展示商家的托管结账页面(continue_url),即使响应中包含该链接也是如此。CLI 会将其省略。此规则仅适用于这些拒付情况。对于 mandatory_acceptance_pending,仍会展示 continue_url。 绝对不要使用已被拒绝的支出请求重新运行 pay ucp-complete。CLI 会清除该请求, 下次完成操作需要获得用户的新批准。

CLI 会根据会话的 checkout_mode 在内部处理凭据类型路由。对于 UCP 原生结账(Link Agent Wallet), 支出请求的 network_id 来自 flow book 之后结账中的 com.stripe.payments → available_instruments 条目 type: "link" → config.network_id(只读,位于 data.ucp_spt_network_id);pay request 会从会话中应用该值。绝不要传入 --network-id、编造 network_id、运行 link-cli mpp decode、探测商家的 HTTP 402 / WWW-Authenticate、初始化 Link UI,或为 Link 调用 Stripe /tokenize。 处理程序契约:Stripe Payments handler for UCP (架构:https://ucp.stripe.com/payments/2026-06-25/schema.json)。USP §7.4: https://github.com/wix/universal-scheduling-protocol/blob/master/specification.md#74-paid-bookings-extension-schema

UCP complete_checkout(CLI 会在内部构建此项):handler_id: "stripe_payments"、 type: "link"、credential.type: "stripe_payment_token"、credential.token = 批准后来自 link-cli 的 SPT(仅在创建支出请求时使用 --credential-type shared_payment_token)。

第 6d 步(验证)属于 pay poll 的一部分;见第 7 步。

付款说明(仅用于错误恢复):

  • at_service:告知用户费用将在预约时支付;绝不要运行 pay request。
  • deposit_required:仅收取当前应付金额;绝不要自行计算定金。
  • 付款时间未知或已变更时,无法预订。若付款时间已变更,请获取新报价。
  • 商家和客户端会在 USP_AGENT_PROFILE_URL 获取文档;默认使用规范 URL。
  • 付款后,按照 next_command 运行 booking-agent flow book poll --wait。确认仅通过 GET 轮询进行。绝不要启动或请求传入的预订 webhook。
第 7 步:完成

pay poll(免费预订或到店付款预订则使用 book poll --wait)会验证预订,在用户选择事件模式时添加日历事件,并以最终答复退出。请原样发送其 user_message:其中包含预订成功的句子、添加事件时的原始日历链接,以及管理预订的链接。然后运行其 next_command(快速检查是否有更新版本的助手),并按照更新中的说明操作。如果 data.calendar.calendar_not_added 为 true,消息中已经说明了这一点;只有用户想再试一次时,才运行 booking-agent flow calendar create-event。如果 validate-skill-compliance 以非零状态退出,请读取 data.error.message,并在宣布完成前补齐缺失的检查。

授权记录(用户询问时)

付款后,或用户索要收据式授权编号时:

booking-agent flow evidence

用通俗语言提供关联标识(预订参考编号、付款参考编号)。绝不要泄露卡片数据、凭据或共享付款令牌。

第 8 步及预订完成后

无需运行任何命令;第 7 步的命令已添加日历事件。

重要事项

  • 绝不违反与用户沟通规则:仅使用原始 URL, 不使用表格,不使用技术术语。
  • pay request 之后,绝不使用与 next_command 不同的支付命令。
  • 绝不在前台运行第一次 pay poll 或 link-auth poll;在交互流程中,使用 pay request --then-complete 或 link-auth connect --wait;也绝不要求用户回复 “approved”或“done”,或多次展示 Link 审批 URL。在后台启动轮询,并在同一轮中发送 URL。
  • 绝不在未询问用户的情况下继续现有会话。当 sessions list 显示与请求匹配的未完成会话时,或 flow init 返回 session_active 时,必须停止并询问用户是继续还是重新开始。 先用 flow status 检查活动会话,然后不作声地继续,这种做法是禁止的——用户必须始终明确作出选择。
  • 绝不将 sessions list 当作预订历史记录。它仅显示此设备上的未完成流程和即将到来的预订。不要根据遗留条目回答“显示我过去的预订”,也不要声称你查询了实际上无法获取的商家历史记录。
  • 绝不使用原始 curl、httpx 或任何 HTTP 客户端调用 USP /availability/query、/bookings、/availability/holds 或 /bookings/*/confirm-payment。始终通过 booking-agent flow ... 完成预订。
  • 绝不使用占位或由聊天输入的个人信息(姓名、电话、电子邮件、地址)。始终通过 link-cli 从 Link 获取——参见个人身份信息(始终来自 Link)。 预订期间,使用 booking-agent flow buyer resolve。只有在用户确认地址后,才能通过 flow search-area 获取地址;对于 at_buyer_location 服务,flow book 会发送已确认的地址。绝不要将地址放入 --notes。
  • 绝不自动选择时段。
  • 在用户回答对应的确切问题之前,绝不传入 --mismatch-confirmed、--details-confirmed、--timezone-confirmed、 --user-confirmed、--policies-accepted 或 --allow-duplicate。绝不要转述或隐藏任何政策条款或链接。
  • 绝不读取或删除 CLI 的状态文件或 link-cli 配置;请使用 flow purge。
  • 绝不在运行 booking-agent 命令的同时执行 sleep 或固定时长的等待;等待命令退出。
  • 绝不跳过日历关卡。
  • 绝不猜测日历路由或令牌变量名称,也绝不在命令行中传入令牌值。

错误

每个错误都会以状态码 1 退出,并包含 data.error.code、data.error.message 和 next_command;未在此处列出的代码应通过执行 next_command 恢复。以下关卡错误无需其他处理:approval_not_surfaced_to_user、booking_canceled_after_payment、buyer_email_invalid、buyer_not_from_link_cli、calendar_gate_not_completed、checkout_prereq_not_completed、context_required、discover_radius_required、link_address_not_found、missing_network_id_for_spt、payment_already_captured、reschedule_at_business、reschedule_booking_not_active、reschedule_failed、reschedule_fee_unsupported、reschedule_price_changed、reschedule_price_unknown、reschedule_same_slot、reschedule_unauthorized、search_area_input_invalid、search_area_not_user_confirmed、search_area_unconfirmed、service_address_unconfirmed、service_details_changed、slot_not_selected、spend_request_replacement_required、timezone_confirmation_required。 支付代码见第 6c 步;所有 reschedule_* 代码的处理方式相同:显示原始 booking_url,并说明用户可以在商家自己的页面上更改(对于 reschedule_price_changed 和 reschedule_same_slot:询问用户是否选择其他时段; 对于 reschedule_failed:再次运行 reschedule availability)。

错误代码原因处理方法
link_auth_gate_not_completed用户退出 Link 登录时运行了 search-area propose 或 buyer resolve让用户登录(运行 link-auth connect,然后在后台运行 link-auth poll,并在同一轮对话中发送 URL),然后重试
link_auth_expiredLink 会话在付款前过期按相同方式让用户登录,然后重试
link_auth_timeout用户未能及时批准 Link 登录运行 next_command:再次在后台运行 link-auth poll(使用同一链接,不要再次发送),或运行 link-auth connect(生成新链接,发送一次,然后在后台轮询)
link_auth_not_started没有待处理的登录时运行了 link-auth poll运行 booking-agent flow link-auth connect,在后台启动 link-auth poll,并发送 URL
ucp_native_required商家不支持原生 v2 结账流程告知用户目前无法在此预订该商家的服务,并提供其他搜索结果
policies_not_accepted、booking_confirmation_required、mismatch_not_surfaced、purge_not_surfaced显示确认标志前未展示对应内容,或内容发生了变化发送 user_message,询问用户,停止;仅在用户确认后运行 next_command
calendar_offer_not_shown在 calendar ask 之前就回答了日历相关问题运行 calendar ask
no_bookable_results、profile_resolve_failed没有商家,或用户选中的商家无法接受预订发送 user_message;提供其他搜索结果
shared_payment_token_not_issuedLink 批准了扣款请求,但未返回共享支付令牌,因此未扣款发送 user_message,再次运行 pay ucp-complete;如果再次失败,告知用户该商家目前无法接受 Link 付款,不要再次要求用户批准
checkout_total_unconfirmed结账总额(税费、费用、折扣)与报价不同,且用户尚未批准显示 data.merchant_quote 中的服务价格、税费和总额,征得用户同意,然后使用 --total-confirmed 重新运行 pay request
payment_timing_changed实时目录中的时间安排与报价不再一致停止操作,重新报价并征得用户新的同意
payment_timing_not_supported实时目录显示了另一种不受支持的时间安排停止操作,并说明目前无法在此预订该服务
mandatory_acceptance_pending商家要求在结账前接受政策或完成其他非付款步骤显示错误中的 continue_url/政策链接;等待后重试 flow book(如果错误来自 pay ucp-complete,则运行 next_command);绝不要代替用户接受
service_not_available_in_area服务坐标超出你提交的 --radius-km 范围扩大搜索范围或选择其他结果;不要通过直接使用个人资料 URL 绕过限制
profile_unreachable无法访问商家个人资料 URL将 data.error.message 中的 URL 告知用户
agent_profile_unresolvable商家无法获取预订助手的平台个人资料,因此未创建预订发送 user_message,然后运行一次 next_command(它会重复使用相同的幂等键,因此不会重复预订);如果再次失败,提供其他时间或商家
reschedule_not_actionable此设备上的会话并非已确认的近期预订从 sessions list 恢复正确的预订;过去的预约或在其他设备上创建的预约只能在商家页面上更改
reschedule_not_allowed商家政策不允许更改此预订显示原始 booking_url,并说明用户可以联系商家更改
session_store_too_new此设备上保存的预订由较新版本的助手写入运行 next_command(booking-agent update check)并按提示操作;绝不要删除或编辑已保存的状态
update_not_confirmed运行 update 时未使用 --user-confirmed先询问用户;仅在用户同意后才传入 --user-confirmed
update_session_in_progress预订尚未完成时运行了 update先完成或取消预订,然后再次向用户提供更新
update_failed / update_not_verified更新未能安装、未能启动,或无法证明其来自官方版本(data.reason);未安装任何未经验证的内容告知用户更新未成功;继续使用已安装的版本
installation_unverified已安装的 CLI 文件与签名的官方版本不匹配,因此无法预订或付款用通俗的话告知用户需要重新安装助手;只有用户同意后才运行 data.reinstall_command,然后重新开始预订。绝不要通过其他方式预订
skill_unverified你加载的 SKILL.md 与此 CLI 发布时附带的签名技能文件不匹配,因此无法预订或付款从现在起遵循 data.skill_text。明确告知用户助手的指令文件已被更改,并询问是否要恢复官方文件;只有用户同意后才运行 data.replace_command,然后再次使用 --skill-path 运行 flow init。绝不要通过其他方式预订
skill_path_invalid--skill-path 指定的文件不存在、无法读取,或不是 booking-agent 的 SKILL.md使用你加载的文件的真实路径再次运行 flow init;如果不知道路径,则不带 --skill-path 运行
skill_output_refusedskill print --output 指定的文件不是已加载的技能文件改为遵循 booking-agent skill print 中的 data.skill_text
给助手团队的备注

如果无法在此处修复故障,输出会将 support_report_offered: true 和 next_command 设为 booking-agent flow support-report。显示该输出中的 user_message(如果有), 然后在同一轮中运行 next_command。它会返回 awaiting_user: support_report_consent, 并在 user_message 中给出问题。

  • 逐字显示该问题,然后停止。不要改写问题或补充细节。
  • 用户同意后,运行打印出的 next_command(booking-agent flow support-report send --user-confirmed)。 用户拒绝后,运行 booking-agent flow support-report decline。无论哪种情况,都要继续运行它返回的 next_command。
  • 备注已提前准备好,发送时保持原样。不要自行撰写备注、选择地址、附加任何内容或发送邮件。
  • 如果发送失败,显示 user_message,并继续运行 next_command。仅在用户提出要求时才重试: 运行 booking-agent flow support-report 并按提示操作。

预订授权

CLI 会对每个特权步骤(预订、更改、取消、付款)进行身份验证,并且会拒绝操作,而不是退回到匿名请求。 搜索、目录和可用时段都是公开的。

  • 商家可能可以浏览,但无法预订。如果因此被拒绝预订,请明确说明暂时无法通过你预订该商家,并提供其他选择。不要重试或 描述其机制。
  • 取消操作使用仅限于该笔预订的凭据,并保存在此设备上。如果凭据已过期或商家拒绝使用,则无需重试:向用户提供 booking_url,并说明他们需要在商家自己的页面上完成取消。

切勿提及这些内部机制。用户只需要知道“我已为你取消”或“你需要在对方的网站上取消这笔预订,这是链接”。

取消即将到来的预订

要取消一项预订,请恢复其会话并运行 booking-agent flow book cancel。要取消多项预订, 或清除未完成的请求,请使用两阶段批量命令。切勿在 shell 中循环运行 sessions resume 和 book cancel。

取消成功后,原样发送 user_message(原始 URL)。其中已经说明:

  • 预订已取消,以及已支付的款项是否已退款;
  • 如果未全额退款,refund_follow_up.steps 中会列出编号步骤,说明如何联系商家 (contact_url、管理页面或商家网站)、应要求退还的确切金额(outstanding_display), 以及预订和订单参考信息;
  • Google Calendar 事件是否已删除(data.calendar.status 为 deleted 或 already_missing)。如果状态为 failed,消息会请用户自行删除该事件,并提供其链接。 重新连接 Google Calendar 后,你可以重试 booking-agent flow calendar delete-event。

切勿将退款步骤缩短为“这笔款项没有退款”。用户需要知道如何拿回这笔钱。

  1. 预览(只读,不会更改任何内容):

    booking-agent flow sessions cancel-open
    

    data.bookings 列出仍可取消的即将到来的预约,data.unfinished 列出未成功预订的 请求,data.held 列出付款正在处理中的请求。每行都包含 user_request、商家和时段。 已取消、已完成、未到场和过去的预订不会列出。

  2. 用通俗的话向用户展示这些行,并询问要取消哪些,然后停止。只选择与用户所问内容 相符的行。切勿假设看起来像测试、实验室或其他请求的行属于此次请求,也绝不要自行 选择行。只有当用户已明确表示要全部取消时,才跳过提问。

  3. 运行已确认的命令,并严格按照用户的选择执行:

    booking-agent flow sessions cancel-open --user-confirmed --session-id <id> [--session-id <id> ...]
    # only when the user said all of them:
    booking-agent flow sessions cancel-open --user-confirmed --all
    

    仅当用户同意删除未完成的请求时,才添加 --forget-unfinished。不添加此参数时,绝不 删除未完成的行。绝不删除 held 行。

  4. 根据 outcome 汇报 data.results 中的每一行。某一项失败不会影响其他项。

    • canceled:原样发送该行的 user_message。其中包含 refund_follow_up 中的退款步骤 (商家的 contact_url、应要求退还的金额,以及预订和订单参考信息)和日历清理结果。 退款时切勿展示订单或结账页面 URL;这些页面仅在付款后立即有效。
    • needs_human:展示原始 booking_url(或 cancel_urls 的第一项),并说明用户需要 在商家的页面上完成取消。
    • failed:说明操作未成功,并在有链接时一并提供。不要自行重试。
    • forgotten:未完成的请求已从此设备中移除。
    • skipped:未执行任何操作;skip_reason 说明了原因。
错误代码原因处理方式
cancel_unauthorized / cancel_forbidden商家拒绝了预订凭据(HTTP 401 / 403)展示原始 booking_url 或 cancel_urls 的第一项;不要重试
cancel_failed其他任何取消失败(商家有响应时会提供 http_status)告知用户操作未成功;存在 booking_url / cancel_urls 时一并提供
cancel_open_selection_required使用了 --user-confirmed,但未提供 --session-id 或 --all先预览并询问用户,然后传入其选择
cancel_open_selection_conflict同时传入了 --session-id 和 --all传入其中一个参数

重新安排即将到来的预约

当用户想要更改(重新安排、调整时间)在此设备上预约的事项时,请移动现有预约。绝不要为此运行 flow init 或预约新的事项,也绝不要先取消再重新预约。

  1. 运行 booking-agent flow sessions list,并选择 actionable: true 且有 booking_id 的条目。如果有多个条目可能匹配,请询问用户指的是哪个预约,然后停止。

  2. 针对该预约运行 booking-agent flow sessions resume --session-id <id>。

  3. 运行 booking-agent flow reschedule start。此命令会检查商家是否允许更改,以及该预约是否仍在未来。

  4. 如果用户尚未说明想改到什么时间,请询问并停止。使用与预约时相同的时间判断方式(指定日期 → --target-date,时间范围 → --from/--to)。

  5. 运行 booking-agent flow reschedule availability [--target-date YYYY-MM-DD | --from ... --to ...]。仅将 selectable: true 的时段以编号或项目符号列表展示,并停止,等待用户选择。绝不要自动选择。时间遵循步骤 4 中相同的时区规则:显示 business_start_display;如果存在 data.timezone_notice,则在列表上方显示一次,并在括号中添加 buyer_start_display。如果用户指定的时间不在列表中,只说该时段目前没有开放。不同查询之间的可用时段可能会变化,而且 CLI 不会说明时段消失的原因,因此不要推测原因。

  6. 运行 booking-agent flow reschedule select --slot-id <chosen by user> --user-confirmed。

  7. 当 awaiting_user: reschedule_confirm 时,用日常用语询问用户是否确认更改,并停止。将两个时间分别放在带标签的独立行中,完全按照提示中的内容显示(先显示商家时间;如果显示用户时间,则将其放在括号中),例如:

    Current time: Tue, Oct 13, 2026, 11:30 AM MST (America/Phoenix) to Tue, Oct 13, 2026, 12:30 PM MST (America/Phoenix)
    New time: Tue, Oct 13, 2026, 1:15 PM MST (America/Phoenix) to Tue, Oct 13, 2026, 2:15 PM MST (America/Phoenix)
    

    绝不要将两个时间范围合并到一句“从……到……”的句子中。只有用户同意后,才运行 booking-agent flow reschedule apply --user-confirmed。如果用户改变主意,则运行 booking-agent flow reschedule abort。

  8. 成功应用更改后,告知用户新的时间。如果 next_command 是 booking-agent flow calendar update-event,则运行该命令,并分享返回的原始 html_link(如果有)。如果日历步骤失败,预约仍已更改;请明确告知用户。

只支持将预约改到同价时段,且仅限商家不收取改期费的情况。绝不要提出补差价或支付费用,也绝不要承诺退款。如果无法在此处更改(reschedule_not_allowed、reschedule_fee_unsupported、reschedule_at_business 或凭据被拒),请显示原始 booking_url(或 manage_urls 中的第一项),并告知用户可以在商家自己的页面上更改。不是在此设备上预约的事项,只能在商家的页面上更改。

退出登录/断开账号连接

当用户要求退出登录、注销,或断开 Link 和 Google Calendar 的连接时,运行:

booking-agent flow logout

用日常用语告知用户已在此设备上退出登录。即将到来的预约仍会保留,因此他们仍可取消这些预约。不要让他们直接使用 link-cli。

要从此设备中忘记一项即将到来的预约(这不同于退出登录,也不是删除商家处的历史记录):

booking-agent flow sessions forget --session-id <id>

仅在用户提出要求时,要清除这名助手在此设备上的所有数据,请运行 booking-agent flow purge。此命令暂时不会删除任何内容:发布 user_message 后停止,只有在用户确认后才运行 next_command。

仅使用 booking-agent flow sessions list 查找未完成的流程或即将到来的预约(actionable: true、booking_id、时段时间)。不要将其用作过往预约列表。

设置

有两个设置对宿主很重要(booking-agent config show 会列出所有设置):BOOKING_AGENT_BUYER_DEVICE_IP(检测到买家设备 IP 时记录的 IP)和 BOOKING_AGENT_USP_AUTH_SCOPED_CREDENTIAL(默认为 required;请参阅预订授权)。用户看不到的故障会自动报告,不包含任何用户数据;将 BOOKING_AGENT_FAULT_REPORTS=0 可关闭此功能。

更多文档

许可证

此技能和 Booking Agent 源代码根据 Apache License 2.0 发布,版权所有 2026 Wix.com。完整条款:https://github.com/wix/booking-agent/blob/master/LICENSE

评论

支持 Markdown