关于 wayai
通过工作区文件和 `wayai` CLI 配置及运维 WayAI hub 的 skill。它涵盖 Agent、工具、评估、旅程、分析和平台同步,适用于构建客户服务或后台运营的团队。
主要功能
- 01以工作区文件管理 hub
- 02拉取和推送 hub 配置
- 03配置 Agent、工具与技能
- 04运行评估并查看结果
- 05测试对话并查看分析
适用场景
- 01配置客户支持或销售 hub
- 02以代码方式维护 hub 配置
- 03测试对话和 Agent 行为
- 04查看 hub 分析与评估结果
MCP 相关
WayAI 支持将 MCP 连接作为一种连接类型:非 OAuth 的 MCP Bearer Token 连接通过 CLI 管理,MCP OAuth 连接则在平台 UI 中配置。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ wayai-pro/ wayai-skill --skill wayai安装后在 Claude Code 中输入/wayai确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/agents-md-template.mdanalytics.mdautomations.mdcalls.mdcommunities.mdconnections.mdreferences/agents/custom-tools.mdinstructions.mdnative-tools.mdprompt-principles.mdroles-and-settings.mdtool-principles.mdreferences/bases/config-as-code.mdexecutors.mdfiles.mdintegrations.mdquerying.mdREADME.mdrecords.mdtoolsets.mdreferences/canonical-example/hub.yamlREADME.mdreferences/canonical-example/agents/support-pilot.mdsupport-pilot.yamlreferences/canonical-example/company-faq/billing.mdrefunds.mdreferences/canonical-example/evals/refund-eligible.yamlreferences/canonical-example/journeys/refund-flow.yamlreferences/canonical-example/knowledge-base/file-types/company-faq.yamlreferences/canonical-example/knowledge-base/toolsets/support-faq.yaml详细介绍
WayAI Skill
WayAI 是 AI Agent 与人们协作的地方,帮助你服务客户并运营业务。每个中心都由 AI Agent 和人工团队组成,涵盖以人为本、跨渠道的支持和销售,以及以任务为中心的后台工作(中心类型)。此工作区以代码形式存储中心——每个中心一个文件夹(hub.yaml + agents/*.{yaml,md} + evals/、journeys/、skills/),并通过 wayai CLI 与平台进行双向同步。
平台是唯一可信来源。 工作区文件是编辑入口——更改通过文件 → wayai push → 平台流转。编辑前务必执行 wayai pull,以获取工作区之外的更改。
如何使用此技能: 本文件是完整的概念地图——此处对 WayAI 的每个基本构件都有足够详细的说明,帮助你决定要构建什么以及要修改哪些文件。字段级架构、各提供商的具体细节和运行机制位于 references/;下方每个领域章节的末尾都有对应深入说明文件的链接——着手编写或调试该领域时,请打开查看。从头开始生成完整中心前,请先阅读一次 references/canonical-example/README.md——其中展示了各部分如何组合。完整的路由表位于文末(参考文档)。
Agent 指南
- 每次会话开始时,先获取最新版本,再做其他事情——每次都要执行,即使只是处理快速任务:更新 CLI,然后检查此技能是否过时,并在过时时刷新。CLI 或技能过时是导致下方某个步骤无法运行的最常见原因。按 工作流 → 现有中心中的步骤 1–2 执行(冷启动:状态机第 1–1c 行),并从第 1b 行复制技能安装命令,不要重新输入——其中的
mkdir -p .claude前缀对 Claude Code 至关重要;第 1c 行说明了安装失败时该怎么做 - 像人一样交流,不要像手册:用户可能刚接触 WayAI——用通俗语言,不要使用行话。回答简短直切重点;不要解释用户没问的内容。如果用户似乎卡住了,或询问某个概念的含义,用一句话回答后继续——不要把回复变成教程
- 操作界面:设置通过
wayaiCLI 和工作区文件完成——这是唯一的自动化入口,且需要文件系统/shell 访问权限(代码环境 Agent——Claude Code、Codex、Cursor、OpenCode)。通过该方式完成下方所有操作。如果你没有 shell 访问权限(应用环境 Agent——Claude Desktop、ChatGPT 等),就无法自行配置 WayAI——请将操作交给用户,使用与下方 OAuth 连接交接相同的形式(一条 URL、一个操作、一条完成确认):“打开https://app.wayai.pro。在那里完成设置,或使用具备 shell 访问权限的 Agent 运行命令——一键提示词安装方式位于https://wayai.pro。完成后告诉我。”之后继续依据此技能回答,绝不要声称自己完成了并未执行的配置 - 只提供来自此技能、工具说明或参考文档的信息
- 不要编造 URL、路径或步骤
- 中心配置通过文件和
wayaiCLI 流转;一次性设置(组织、OAuth)通过平台 UI 完成。预览版发布至正式版现在既可通过 CLI(wayai publish)完成,也可通过 UI 完成 - 编辑前务必执行
wayai pull -y——以获取工作区之外的更改 - 编辑后务必立即执行
wayai push -y——编辑和推送是一个整体操作。社区除外:推送会直接修改线上社区(没有预览),因此应先展示更改(wayai push communities/<folder> --dry-run),并且仅在用户明确同意后推送 - 绝不自动提交——展示
git diff,等待用户批准
快速判断:我能做什么?
| 实体 | 操作方式 |
|---|---|
| Hub 设置、Agent、Agent 指令、工具、看板、状态、技能、评测、旅程、自动化、自定义工具 | CLI(wayai push);自动化可在应用中暂停 |
| 联系人和组织列表(组织的通讯录,自动化以此为目标) | UI(组织设置 → 联系人)或 API(/api/contact-book)——绝不使用 hub.yaml。请参阅自动化 |
| 联系人在某个基础中的客户记录(对话提及该联系人时,客户范围的工具集所服务的记录) | CLI(wayai contacts link-customer / unlink-customer,仅限浏览器登录)或 API(/api/contact-book/contacts/:id/customer)——请参阅将联系人关联到其客户记录 |
| Hub 列表(Hub 对通讯录设置的自有筛选条件,自动化以此为目标) | CLI(hub.yaml 中的 contact_lists:、wayai push)或 UI(Hub → 自动化 → 列表) |
评测旅程(hub-as-code)——扁平文件夹中的 journeys/<slug>.yaml | CLI(wayai push / wayai pull;首次创建后执行 pull 以同步步骤 ID) |
| 连接——非 OAuth(Agent 提供方、STT/TTS、工具 API 密钥、MCP Bearer Token) | CLI(根据组织凭据自动创建) |
| 连接——OAuth(WhatsApp、Instagram、MCP OAuth) | 平台 UI |
| 直接设置/轮换连接的凭据(包括生产环境) | CLI(wayai set-connection-credential)或 UI |
| 组织凭据——创建 / 轮换 / 编辑 | CLI(wayai create-credential / wayai update-credential)或 UI |
| 组织级共享技能(org-as-code) | CLI(wayai org pull / push / diff) |
| 基础——架构、记录、关系、文件、工具集(数据界面) | CLI(wayai bases、wayai records、wayai record-types 等;通过 wayai pull/push bases/<base> 进行配置即代码)——请先打开 references/bases/README.md |
| 将技能同步到提供方 | CLI(wayai sync-skills) |
| 对话测试 | CLI(wayai send-message、wayai conversations、wayai delete-history) |
| 诊断 Hub 异常的原因(音频/TTS 未送达、Agent 无响应、工具故障)——首先检查连接/凭据的运行状况 | CLI(wayai alerts)——显示活跃的状态与通知警报(例如,无效的提供方密钥会显示为 connection_auth,通常对应 401)。请先运行此命令,再阅读代码或提交报告 |
| 诊断无法解释的 Agent 回复(日期错误、忽略规则、虚构值)——不要根据对话记录推断;请查看 Agent 实际收到的内容(解析后的提示词、渲染后的上下文、注入的时间戳、工具调用) | CLI(wayai conversations <id> observability [--message-id <id>])——请先运行此命令,再编辑指令 |
| 在已结束的对话中记录事后业务结果(例如客户已购买),作为分析维度 | CLI(wayai conversations <id> annotate --set key=value [--type ...]) |
| 分析 | CLI(wayai analytics、wayai analytics query) |
| 成本 / Token 消耗分析(按消息、模型、Agent、角色或凭据) | CLI(对 message 表运行 wayai analytics sql)——请参阅 references/analytics.md——data.* 路径必须显式转换类型才能运行,且还需遵循确保求和结果正确的规则 |
| 评测运行和结果 | CLI(wayai run-eval、wayai eval-results) |
语音通话——Realtime 连接、pilot_voice Agent、call_utterance 引导监控器 | CLI(wayai push)或 UI——请参阅 references/calls.md |
| 通话评测——通话模式文本运行、评分后的机器通话 | CLI(wayai run-eval --call-mode、wayai eval call)——请参阅 references/evals.md |
| 列出评测场景 / 对评测结果运行原始 SQL | CLI(wayai evals、wayai evals sql) |
| 将生产对话捕获为评测 | CLI(wayai eval capture <conversation_id>) |
| 将生产对话捕获为旅程(完整的多轮对话记录) | CLI(wayai eval journey capture <conversation_id>) |
| 停止正在运行的评测会话 | CLI(wayai eval session stop <session_id>) |
| 删除评测会话 / 运行历史记录 | CLI(wayai eval session delete <session_id>,或使用 --all 删除 Hub 上的所有会话) |
| 报告 Bug | CLI(wayai report create) |
| 工作区发现 | CLI(wayai list) |
| 社区——列出组织的社区、读取 / 轮换 / 关闭加入链接、读取统计信息和仅限邀请社区的访问列表 | CLI(wayai communities,仅限浏览器登录)或 UI——请参阅 references/communities.md |
社区——名称、设置(谁可以加入:admission)、规则、加入链接的启用/关闭状态、聊天室、课程(模块、课程) | CLI(wayai-ws/communities/<folder>/、wayai pull/push communities/<folder>;push 会编辑线上社区)或 UI——请参阅 references/communities.md。审核:UI |
| 组织——创建 | CLI(wayai org create)或 UI |
| 组织——更新、删除 | UI |
| 将预览发布/同步到生产环境 | CLI(wayai publish,别名为 wayai sync)或 UI |
| 删除 Hub | UI |
| 复制预览、设置/清除预览标签 | CLI(wayai replicate / wayai relabel)或 UI |
| 团队、团队用户、Hub 用户、管理员、联系人审批 | UI(Hub → 用户选项卡) |
| 组织标签(创建;编辑显示名称/颜色——slug 永久不变) | UI(在 hub.yaml 的 tags: 中通过 slug 引用) |
实体层级
Organization ← CLI (`wayai org create`) or UI
├── Org Credentials ← CLI (`wayai create-credential`/`update-credential`) or UI — API keys stored once, reused across hubs
├── Org Tags ← UI — gate which credentials each hub can resolve and which contacts it sees
├── Org Skills ← CLI (`wayai org pull/push`) — shared skills, fan out to linked hubs
├── Bases ← CLI (`wayai bases`) — the Data surface. Org-level, NOT inside a hub (see Bases)
├── Contact book ← UI (Contacts) or API — contacts + org lists that automations target. Org-level, NOT in `hub.yaml`
└── Hub ← CLI (`wayai create`, or auto-creates on push) or UI; publish/sync via CLI (`wayai publish`) or UI
├── Connections ← auto-created from org credentials on push (non-OAuth); OAuth via UI
├── Channels ← auto-provisioned, never authored (see Channels)
├── Agents ← CLI — `agents/<slug>.yaml` + `<slug>.md`
│ ├── Tools ← CLI — native, custom HTTP, MCP, delegation
│ └── Skill links ← CLI — `skills:` block in agent YAML
├── Kanban statuses ← CLI — `hub.yaml` (workflow stages for conversations)
├── States ← CLI — `hub.yaml` (JSON-schema data agents read/write)
├── Skills ← CLI — `hub.yaml` `skills:` + `skills/` folder
├── Evals + Journeys ← CLI — `evals/`, `journeys/`
├── Hub lists ← CLI — `hub.yaml` `contact_lists:`; filters over the contact book (labels, scope tags)
├── Automations ← CLI — `hub.yaml`; paused in the app; each targets a hub list or an org list by name
└── Teams + Users ← UI (Hub → Users) — teams, admins, team users, hub users
设置顺序:组织(CLI wayai org create 或 UI)→ 组织凭证(CLI 或 UI)→ Hub(CLI wayai create,或推送时自动创建,或 UI)→ 通过 CLI 配置 Agent、工具和连接。
创建 Hub 时会自动创建 wayai 连接(原生工具),无需设置。
Hub 类型
| 类型 | 对话 | 渠道 | 用例 |
|---|---|---|---|
chat | 每位最终用户一个 | WhatsApp、Instagram、Email、Telegram、App | 以人为中心:支持、销售、服务台 |
task | 每位用户多个 | 仅限 App | 以任务为中心:发票、库存、审批 |
判断方式:需要外部渠道(WhatsApp/Instagram/Email/Telegram)→ chat。处理对象/任务 → task。
AI 模式与对话模型
Hub 级别的 ai_mode 用于设置 AI 的行为:
| 模式 | 行为 |
|---|---|
pilot | AI 自主处理最终用户 |
copilot | AI 为支持团队建议回复(不向渠道发送) |
pilot+copilot | 根据当前回复者动态切换 |
turned_off | 禁用 AI;仅由人工处理 |
对话是最终用户与 Hub 之间的运行时会话(配置实体定义行为;对话和消息是它们作用的对象):
conversation_status:agent(由 AI 处理)|team(由人工团队处理)|ended(已关闭并归档)- 状态决定当前生效的 Agent 轨道:状态为
agent→ Pilot 轨道通过渠道向最终用户回复;状态为team(且模式为copilot/pilot+copilot)→ Copilot 轨道起草建议,供团队在/support中查看 - 轨道切换:使用
transfer_to_team工具(agent → team),或由团队在支持 UI 中交回处理权(team → agent)。transfer_to_agent/consult_agent用于在同一轨道内的 Agent 之间切换 - 关闭方式:Agent 的
close_conversation工具;转换为isTerminalStatus看板状态(通过任何界面——Agent 或 harness 工具、团队拖放操作、REST);团队 UI;或 Hub 的auto_close_inactive_days。已结束的对话会归档并显示在“已结束”标签页中;在conversation_retention_days期限内,仍可使用wayai conversations <id> annotate进行事后标注 - Agent 的回复文本会自动发送——没有发送消息工具;工具用于执行回复以外的操作
看板状态与上述内容相互独立:它跟踪工作流阶段(如 qualified 这样的自定义 slug),而非由谁回复。
Agent 角色
| 角色 | 轨道 | 每个 Hub 的数量 | 描述 |
|---|---|---|---|
pilot | Pilot | 1 | 自主响应最终用户 |
copilot | Copilot | 1 | 为支持团队提供回复建议 |
pilot_specialist / copilot_specialist | Both | 多个 | 委派目标 — 通过 transfer_to_agent 完整转交 |
pilot_advisor / copilot_advisor | Both | 各 1 个 | 通过 consult_agent 提供建议;随后归还控制权。仅在模型连接上运行,绝不在托管 Agent 连接上运行 |
monitor | Background | 每个触发器触发时 1 个 | 静默观察;在 user_message 上,其规则可以采取行动 — 向负责回复的 Agent 提供你编写的备注、运行另一个 monitor 以进一步查看,或将对话移交给另一个 Agent 或人工团队;这些操作均对同一条消息生效。在 assistant_reply 上,它是回复关卡:在发送任何内容之前读取已拟好的回复,并可将其暂缓供团队处理,或让 Agent 重写一次。在 call_utterance 上,它会监控实时语音通话,并可通过你编写的备注引导语音。在 automation_fire 上,它是自动化的关卡:每次运行前决定运行、使用另一个 Agent 运行或跳过;在 automation_item 上,对于列表运行中的每个联系人,决定启动、使用另一个 Agent 启动或跳过。每个触发器最多只能启用一个 monitor,但 manual 除外(可启用任意数量 — 只有在另一个 monitor 调用它们时才会运行),两个自动化关卡也除外(可启用任意数量 — 每个自动化都会指定自己的关卡) |
conversation_evaluator / message_evaluator | Background | 各 1 个 | 异步质量评估;不参与常规路由。其 evaluation_variables 会提供给 Analytics;message_evaluator 还会为评估运行打分 |
summarizer | Background | 1 | 首个 pilot/copilot 创建时自动配置,使用其连接;但如果该连接是托管 Agent 连接,则不会如此(summarizer 仅在模型连接上运行)。将较早的消息汇总为滚动 JSON 摘要,并以保留的 slug conversation_summary 存储为对话状态。当有效输入令牌数超过 summarizer Agent 的 summarization_threshold_tokens 时,在轮次结束后异步触发(默认值为 120000;见下文)。非后台 Agent 会将摘要作为 <conversation_summary> 块查看,并可调用 expand_summary(section_id) 获取原始消息。架构可由用户编辑,但必须满足锚点不变量(sections[].id、message_id_start、message_id_end) |
pilot_voice | Pilot(实时通话语音) | 多个(一个负责接听通话) | Hub 实时 AI 语音通话所用的语音:与来电者交谈,并根据其指令将问题交给 pilot 回答。仅绑定 Realtime 连接;文本轮次、评估运行或转交操作均不会运行它 — 参见语音通话 |
consultant | 与轨道无关(按需) | 多个 | 由人(和 Agent)在可见的咨询线程中咨询。绝不作为 pilot/copilot 响应者,不会自动触发,也不是转交或顾问目标。顾问在 AI 的轮次中提供建议且不可见;consultant 则由人(和 Agent)在可见线程中咨询。 咨询轮次按常规前台操作计费。支持团队在支持撰写框中标记它即可进行咨询(support-inbox.md) |
transfer_to_agent 可将任务交给任何同轨道 Agent — *_specialist 或入口 pilot/copilot,因此 pilot 可充当集线器-辐射式路由器(specialist 可将跨领域请求转交回 pilot,以便重新分派)。跨轨道、advisor、consultant 和后台角色均不能作为转交目标。
有关角色流程、委派和设置详情,请参见 references/agents/roles-and-settings.md。
交接上下文工程
当对话更换负责方时(transfer_to_agent 或 transfer_to_team),接手者会从头重建历史记录,其中之前每个 Agent 的发言都会显示为无法区分的 assistant 消息,而人工团队的发言则没有署名(模型无法分辨哪些发言是它自己写的,哪些是继承来的)。运行时会自动弥合这一差距——请编写 Agent,使其能够与运行时协作:
- 运行时会在每次
transfer_to_agent和transfer_to_team时持久保存一条交接标记(This conversation was handed off from X to Y.),并在接收方 Agent 的首轮发言中提供一条一次性续接说明(仅适用于 Agent→Agent——团队交接没有可接收说明的 AI 接收方)。这些内容不需要你编写,因此不要在 Agent 的指令中加入“你刚刚接手了此对话”之类的措辞;运行时会处理,而且重复添加会造成冗余。 - 每个 Agent 的指令都应以其身份介绍开头——
You are <Agent Name>, the <role/purpose>…。运行时会在交接时强化身份信息,但系统提示词是最强的信号,也是每个常规轮次中唯一始终存在的身份信息;只有当 Agent 知道自己就是 Y 时,交接标记中的“……交给 Y”才有意义。 - 专家 Agent 必须实际完成工作,不能把任务推回去。运行时会阻止将任务委派给本轮中之前已经接手过该对话的 Agent(包括 A→B→A 及更长的重复交接链);交接会被拒绝,并返回错误,提示 Agent 完成任务、转交给其他 Agent,或将控制权交还给用户。因此,不要编写会本能地把对话交还给委派方的
*_specialist指令,否则只会触发防护机制。(每个用户轮次都会重置交接链,因此在后续轮次中将任务重新转交给之前接手过的 Agent 没问题。)
Summarizer Agent 配置
Summarizer Agent 在 agents/summarizer.yaml 中以顶层键 summarization_threshold_tokens 暴露摘要阈值(默认值为 120000,最小值为 1000,最大值为 1000000)。测试时可调低该值;对话很长时可调高。Summarizer 的 connection 默认使用 pilot 的连接(如果 pilot 使用托管 Agent 连接,则默认没有连接;请在模型连接上添加 summarizer);编辑 agents/summarizer.yaml 可更改其模型或系统提示词。conversation_summary 状态的架构与其他状态一样支持往返转换——允许添加锚点之外的字段,但锚点不可缺少。(此前这是 hub 级别的 hub.yaml 设置,现已迁移至 summarizer Agent。)
连接与凭据
连接是已配置的连接器实例(目录条目:大模型提供商、渠道 API、工具 API、语音服务),附带凭据并限定在一个 hub 内。组织凭据在组织级别存储一次密钥;连接通过名称引用它——原始密钥绝不会进入 YAML。
| 类别 | 示例 |
|---|---|
| Agent | OpenAI、Anthropic、Google AI Studio、OpenRouter、xAI(AI 必需) |
| 渠道 | WhatsApp、Instagram(OAuth — 仅限 UI);Resend(电子邮件)、Telegram(API Key — 自动创建) |
| 工具 — 原生 | Wayai(自动创建)、External Resources(API Key)、Base Toolset(Bearer Token — 绑定到某个基础工具集的令牌) |
| 工具 — 自定义 | 用户定义的 HTTP 端点(API Key、Bearer Token、Basic Auth) |
| 工具 — MCP | 外部 MCP 服务(Streamable HTTP)— 通过 CLI 使用 Bearer Token;通过 UI 使用 OAuth |
| 语音 | STT 转写收到的语音消息(Groq、OpenAI、ElevenLabs)— 只有在启用了 STT 连接的 hub 上,应用的消息编辑器才会向最终用户和团队成员提供语音消息按钮;TTS 合成语音回复(OpenAI、Groq、ElevenLabs、Google),各语音响度相同 |
| 实时 | OpenAI GPT-Live — 实时 AI 语音通话使用的语音,仅供 pilot_voice Agent 使用 |
自动创建规则: 推送 hub.yaml 时,系统会根据匹配的组织凭据自动创建非 OAuth 连接(Agent、STT、TTS、Realtime、工具 — 自定义、通过 Bearer Token 连接的工具 — MCP)。匹配会遵循组织标签(无标签的凭据是全局凭据——每个 hub 都能使用;带标签的凭据仅对至少共享其中一个标签的 hub 可见)和凭据 environment。OAuth 连接必须先在 UI 中设置。
OAuth 连接交接(随时可进行,不限于引导设置期间): OAuth 连接(WhatsApp、Instagram、MCP OAuth)无法通过 CLI 创建——需要一次性 UI 流程。任何时候需要 OAuth 连接时——无论是首次设置,还是之后(新增渠道、OAuth MCP 服务)——都应将完整路径的连接选项卡深层链接 https://app.wayai.pro/settings/organizations/<orgId>/hubs/<hubId>/connections?connector=<slug>(<orgId>/<hubId> 来自 wayai status --json;<slug> ∈ whatsapp、instagram、mcp-server)提供给用户,然后等用户完成后运行 wayai pull -y。该深层链接会打开连接选项卡(如果连接已存在,例如需要重新授权,还会突出显示相应连接器);要创建连接,用户需点击添加连接,选择 <Connector> 卡片,选择 OAuth,然后完成提供商的授权流程。请使用此选项卡链接形式——不要使用 /connections/new?connector=…,因为它需要 connector_id UUID,且默认选择第一种认证类型(MCP → Bearer Token),因此无法使用 MCP OAuth(参见 navigation.md)。
有关各提供商的设置、凭据绑定(credential:、no_auth:)、标签以及生产凭据解耦,请参见 references/connections.md。
渠道
hub 上的通信端点——消息抵达和回复送达的位置。渠道绝不会在 YAML 中编写:
- hub 创建时会自动创建
app(应用内聊天)和system(内部)渠道 - 创建渠道连接时,会自动配置 WhatsApp / Instagram / Email(Resend)/ Telegram 渠道
渠道唯一性(电话号码 / 页面 / 收件地址)仅在生产 hub 之间强制执行——预览环境可以与对应的生产环境共用端点;外部渠道可通过 #test CODE 测试人员注册功能在预览环境中进行测试(参见 Hub Environments)。
语音通话
chat hub 可以在 Web 应用的聊天视图中接听实时 AI 语音通话:来电者按下开始语音通话,听到一段提示,告知他们正在与 AI 对话(WayAI 的提示,或语音 Agent 用该语言自行说出的开场白),然后开始语音交流。任何 hub 都可以为他们配置。WayAI 可以在整个平台注册范围内关闭语音通话;关闭期间,wayai push 会拒绝创建 Realtime 连接或 pilot_voice Agent,也会拒绝启用下方列出的任何组件,并显示 Voice calls are not enabled for this platform, so …——看到此提示时,请停止操作并告知用户。
- 语音由使用 Realtime 连接(基于组织自己的 OpenAI 项目密钥)的
pilot_voiceAgent 提供。其设置包括语音、语言、通话限制、是否录音(默认关闭)、等待答案时是否播报进度提示,以及固定话术(问候语、提示、重复内容、道歉语、超时提示)的措辞;它遵循的唯一规则是自身指令:如何交谈,以及如何将每个问题交给 pilot(请从示例开始) - 答案由 hub 的 pilot 提供:语音将问题转交给 pilot,正如其指令应当要求的那样;pilot 会针对语音转交的每个问题执行一次常规轮次——包括工具、监视器和回复门控。是否允许 AI 回答,遵循与文本相同的规则;当这些规则不再允许回答时,通话就会结束(转接给团队、接管、关闭等)
- 具有副作用的操作须等来电者口头确认;
call_utterance监视器可以在通话过程中引导语音;wayai run-eval --call-mode和wayai eval call可用于评估通话 - **计费:**语音转交的每个问题计为 1 次操作,此外还会按通话连接时长按分钟计费
设置、通话结束方式、团队可见的信息、录音、计费和限制:references/calls.md。
工具
在 agents/<slug>.yaml 中为每个 Agent 分配能力。请记住:回复文本不需要工具——工具用于其他所有操作。
| 类型 | 来源 | 方式 |
|---|---|---|
| 原生 | 平台内置工具(例如 update_kanban_status、get_state、send_files、close_conversation、read_file) | 在 tools.native 下按名称列出 |
| 自定义 | 由你定义的 HTTP 端点 | 在 tools.custom 下使用 connection、method、path、config 定义 |
| MCP | 来自已连接 MCP 服务的工具 | 双来源——在每个 Agent 的 tools.mcp 下声明,和/或在平台 UI 中分配。wayai push 会在一次运行中发现并分配工具;存在 mcp 键(即使值为 [])时,以该键为准;省略该键则保留在 UI 中分配的工具。参见 native-tools.md |
| 委派 | Agent 间委派(transfer_to_agent、consult_agent、start_consult_thread)、Agent 到团队(transfer_to_team),或 Agent 到 hub(delegate_to_hub、start_consult_thread) | 在 tools.delegation 下使用 target 定义(Agent 显示名称、团队名称或 hub 名称) |
元工具(get_tool_schema、execute_tool)使 Agent 能够调用其架构未包含在内联列表中的工具。完整的原生工具目录和参数:references/agents/native-tools.md;自定义工具架构:references/agents/custom-tools.md;有关设计要公开的工具和参数:references/agents/tool-principles.md。
Hub 委派(delegate_to_hub)
将另一个 hub 视为顾问。该工具会在目标 hub 中创建一个任务对话,目标 hub 的答复会以消息形式异步返回到发起请求的咨询线程中,因此标记 Agent 的轮次会立即结束,不能等待结果。
- type: hub
tool: delegate_to_hub
target: Billing Hub # a PRODUCTION (published) hub in the same organization
context_boundary: summary # instruction | summary | transcript
target必须是同一组织内已发布(生产环境)的hub_type: taskhub。 选择生产环境是为了与分支语义保持一致;选择 task 是因为任务 hub 会为每个请求创建独立对话,而chathub 会为每位用户保留一个对话,因此每次委派都会堆积在同一个线程中,导致客户之间的信息混杂。跨组织、未发布或chat类型的目标会导致推送失败(运行时调用该工具也会失败)。- 目标 hub 必须关闭创建的对话——关闭就是完成信号。请求文本会指示它关闭对话,但如果目标 hub 的 Agent 永远无法关闭对话(没有
close_conversation工具,也没有终结状态的看板状态),请求方就会一直等待。(由 Agent 发起的咨询会带有过期时间——参见start_consult_thread;由团队发起的 hub 委派没有过期时间,因此要确保目标 hub 有办法完成任务。) context_boundary是数据敏感性决策,不是调优参数。 各 hub 的团队成员及其可查看的信息可能不同,因此请谨慎选择——不存在适用于任意 hub 对的安全默认值:
| 值 | 传递到目标 hub 的内容 |
|---|---|
instruction | 仅 Agent 自身的请求。不包含对话中的任何内容。 |
summary(默认) | 请求 + 滚动更新的对话摘要。 |
transcript | 请求 + 完整的客户对话记录。 |
在任何设置下,内部咨询消息都不会传递;模型既不能选择目标,也不能扩大边界——这两项均由管理员配置。
- 仅可在咨询线程中使用,结果也会在该线程中送达,因此请将它分配给
consultant角色的 Agent。如果结果在对话关闭后到达,则会被丢弃(线程会记录为cancelled_at_close)。 - v1 中只能通过 CI/YAML 配置——在 hub 选择器和边界控制功能上线之前,平台 UI 的工具“添加”网格不会显示它,因为配置时需要同时做出上述两项选择。
Agent 发起咨询(start_consult_thread)
允许非后台 Agent在支持团队可见的咨询线程中向配置好的顾问(或合作方中心)提问——这是这套统一咨询机制的第三种发起方式,另外两种分别是人工标记顾问,以及 Agent 委派给中心。
- type: agent
tool: start_consult_thread
target: Billing Expert # a `consultant`-role agent on this hub
- 模式取决于目标对象。 同一中心的顾问会在工具调用中作答;合作方中心则会异步作答——提问的 Agent 会结束当前轮次(“我去确认后再回复你”),答案送达后会自动恢复。同步咨询耗时过长时会自行转为异步,因此 Agent 指令必须针对任何目标对象处理“答案稍后送达”的情况。顾问与除试点人员、副驾驶及其专家以外的所有角色一样,只能使用模型连接,不能使用托管 Agent 连接(
Claude Agent (Managed)):不允许在此类连接上保存顾问;若向使用此类连接的顾问发起咨询,或顾问没有连接,则会在发送任何内容前拒绝请求。 - 默认关闭顾问→顾问链式咨询;启用后仅支持同步模式——在工具上设置
allow_consultant_chain: true即可允许此类咨询,但目标必须是同一中心的顾问。monitor、评估器和summarizer永远不能发起咨询。 - 预算限制会强制执行:包括咨询链深度、双向循环拒绝(中心内 Agent A → B → A、跨中心中心 A → B → A)、每次 LLM 调用的上限,以及会话级持久上限。每个咨询轮次都会计入前台操作,因此这些上限可防止 Agent 在无人看管时不断增加成本。
- 不会让任何请求永远处于待处理状态:未获答复的咨询会过期,并向提问者返回超时通知;会话关闭时仍未完成的咨询会记录为
cancelled_at_close。 - 团队成员在 Agent 发起的线程中发帖后,会永久接管该线程——该线程不再自动唤回 AI,后续对该线程发起的咨询会收到固定通知:“已由团队接管”。
- v1 中仅通过 CI/YAML 配置,与
delegate_to_hub一样。
完整参数和 YAML 格式:references/agents/native-tools.md。
看板与状态
看板状态是对话的工作流阶段(显示在支持/任务视图中),在每个 hub 的 hub.yaml 中定义:
- 标识:不可变的小写
slug(存储在对话、分析数据和工具参数中;永远不能重命名)+ 可自由编辑的显示name。工具只接受 slug(显示名称会作为标签一并传递)——指令必须通过 slug 引用状态 - 行为标志:
isInitialStatus(每个 hub 必须且只能有一个)、triggersAgentResponse(状态转换会触发一轮 Agent 响应)、allowsAgentUpdate、isTerminalStatus(进入该状态会关闭对话;每个 hub 至多一个)、isSchedulingStatus(以及eventName)。某些组合互斥——每次写入时都会在服务端验证 allowed_next_statuses— 可选的状态转换允许列表,在运行时的所有界面上强制执行,但有两种例外:非 Agent 调用方进入终止状态(REST 界面,无论是看板还是程序化调用;Agent 仍受限制),以及对已处于终止状态但仍未关闭的对话执行重新关闭——任何非 Agent REST 调用方均可执行,包括程序化调用;但 Agent 只有在复用已存储的结果、该状态未声明任何结果,或其所选结果不受限制时才能执行。省略 = 不受限制;拒绝[](请使用isTerminalStatus)- 结果 — 只有终止状态可以声明
outcomes: [{slug, name, color?, from_statuses?}](关闭处置结果,例如已解决/已取消)。from_statuses是非空的来源 slug 允许列表;省略表示接受来自任何来源的结果。真正的看板终止状态转换必须有符合条件的结果,并会将其 slug 存储为分析数据,路径为data.meta.outcome。Agent 关闭操作(close_conversation、harnessend_conversation)会通过该转换处理,并受相同限制。团队关闭按钮(网页端和移动端)也会通过该转换处理,并先询问结果;但作为非 Agent 调用方,它仍适用上述allowed_next_statuses的终止状态例外;如果当前对话状态没有符合条件的结果,则会改为直接关闭,以免对话无法关闭。闲置自动关闭和POST /:id/close不使用结果 - 后续跟进 — 每个状态可配置定时消息:
inactivity(静默一段时间后)、before_event(活动开始前的倒计时)、inactivity_after_event(访问后的跟进——第一步从活动时间开始计时,之后每一步从上一次提醒开始计时),或inactivity_after_before_event(相同的跟进方式,但从某个特定的before_event触发时开始,由after_followup_id指定)。后三种要求设置isSchedulingStatus;只有对话中包含scheduled_event_date才会启用这些跟进,该字段须在状态转换时提供,不能在状态配置中提供。支持阈值/时间单位、静默时段和排除节假日 - 状态转换时的附加上下文 —
triggersAgentResponse状态可以声明additional_context_schema(团队在状态转换时填写的 JSON-Schema 格式)+additional_instructions(包含{{path.to.field}}/{{additional_data}}占位符的文本模板,会注入触发的轮次) - 泳道 — 可选的看板展示分组;不影响行为
完整的字段规范、约束矩阵、警告和示例:references/kanban.md。
状态数据是 Agent 在对话期间读写的 JSON Schema 数据——通过原生工具(get_state、update_state、set_state_path、reset_state,均通过其 slug 指定状态)以及 {{state(scope, slug)}} 指令占位符访问。每个状态都有 conversation 或 user 范围、一个 json_schema,以及可选的 initial_value(预填充的虚拟记录,会一直显示到首次实际写入;省略则在写入前保持静默)。
**看板与状态数据:**看板用于追踪工作流进度;状态数据用于追踪结构化数据。两者可以共存。Schema 和模式:references/states.md。
技能
附加到 Agent 的技能。内容以真实文件的形式存放在 skills/<skill_name>/ 下(对于技能内容,文件系统是事实来源);hub.yaml 中的 skills: 只声明名称、skill_name 和描述。
| 类型 | 内容 | 运行时行为 |
|---|---|---|
skill | 版本化能力包——SKILL.md(frontmatter 中包含 name + description)+ 可选的 references/ | Agent 通过 skills/<skill_name>/… 读取其文件(list_files、read_file、{{file_content(skills/…)}});在 Agent 操作的任何文本(指令、设置、监控备注、自动化、看板后续事项、自定义工具、技能描述)中,凡是在 resources/ 下引用的技能,保存和推送时都会被拒绝。以可调用工具的形式注入(默认,适用于所有提供商),或在提供商容器中原生运行(use_native_integration: true,仅支持 Anthropic/OpenAI;在 wayai push 时自动同步到提供商,连接失败或较晚添加连接后可通过 wayai sync-skills 重新同步) |
知识资源已停用:文档(常见问题、目录、政策)存放在组织的知识库中,Agent 通过 Base Toolset 连接读取 data/<file type>/… 下的内容(知识库)。技能不需要 type。
Agent 在 agents/<slug>.yaml 的 skills: 块中关联技能(按名称和 skill_id,并指定 priority)。跨 Hub 共享的组织级技能存放在 wayai-ws/org/(skills.yaml + skills/<skill_name>/),通过 wayai org pull/push 管理(推送会分发到已关联的 Hub)。推送采用声明式方式:从 hub.yaml 中移除某项技能(包括最后一项)会将其删除。
在技能之前拉取的文件夹包含 resources:(位于 hub.yaml 和 Agent 文件中)以及 resources/ 文件夹(组织级配置为 org/resources.yaml)。wayai push、diff 和 publish(以及 org push/org diff)会在发送任何内容前拒绝处理这些文件夹;wayai pull(wayai org pull)会转换它们,并在遇到 resources/ 中不是其写入的技能文件夹或不在其 skills/ 中的内容时停止并指出该内容(知识备份:请将其移出工作区)。这需要 @wayai/cli 0.3.234 或更高版本(wayai update):较旧 CLI 推送旧布局文件夹时会被拒绝,并返回指出该文件夹的 400;推送已转换的文件夹时不会更改任何技能;对旧布局文件夹执行 wayai pull 时,在比较阶段会遇到相同的 400,无法列出变更(请在拉取前更新);执行 wayai org pull/push/diff 和 sync-skills 时会收到 404(旧路径已不存在)。详情:references/skills.md。
文件处理(文本与二进制、10 MB 上限)、技能编写和执行模式:references/skills.md。
Base(数据层)
Base 是组织级的数据容器,是各个 Hub 背后的事实来源。Hub 保存对话;Base 保存这些对话所作用的结构化数据。使用相同的 CLI、相同的登录和相同的工作区;Base 是独立实体,有自己的子树和 promote 命令。
- **基本元素:**记录类型 → 记录、关系类型 → 关系、文件类型 → 文件,此外还有 Actions 和 toolset(Agent 调用的精选 MCP 工具)、触发器和入站 Webhook(接收和发送变更)、外部数据源(通过外部 API 为记录类型提供数据),以及种子测试数据(隔离的评估数据)
- **唯一规则:**配置写入(记录类型、关系类型、文件类型、触发器、入站 Webhook、Actions、toolset、种子数据)只能写入 preview Base;数据写入则在任何 Base 上都可用。晋升由人工执行——运行
wayai bases promote <prod> --from <preview> --dry-run,然后等待 - **ID 不可变。**Base、记录类型、关系类型、Action 或 toolset 的
id就是其标识;不能重命名,只能新建并迁移。请预先选择稳定的小写 slug - 工作区:
wayai-ws/bases/<base>/(包含base.yaml和每个实体对应的文件),通过wayai pull bases/<base>/wayai push bases/<base>操作。如果pull/push同时指定hubs/和bases/中的目标,将被拒绝,绝不合并 - 命令:
wayai bases,以及顶层的records、record-types、relationships、relationship-types、query-relationships、files、file-types、attachments、toolsets、actions、triggers、inbound-webhooks、seed(每个命令都接受--base),以及wayai bases tokens|secrets|sql|import|batch|providers - **连接 Hub:**通过 Base Toolset 连接,原生 Agent 可使用 toolset 中的工具,并可在
list_files和read_file中访问其位于data/<file-type>/下的文档;使用write_file和edit_file写入文档(references/connections.md);由 harness 支持的 Agent 使用指向该 toolset 的普通 MCP Server 连接(不带get_url或put_url的连接: URL tools and hub agents);评估则指定target_base:。组织的文档存放在这里,也就是其知识库(references/bases/files.md);技能仍保留在 Hub 中(技能)
在进行任何 Base 操作前,请先阅读 references/bases/README.md——其中包含完整的对象模型,并指向下面各领域对应的文件。本节内容不足以用于编写架构。
评测
运行真实 Agent 及其真实工具并为结果评分的测试场景。基本要素:
- 场景(
evals/<name>.yaml或evals/<set>/<name>.yaml)——可选的多轮history、一条input、一个expected响应(文本和/或tool_calls),以及可选的evaluator_instructions。由 hub 的message_evaluatorAgent 评分;如果某个必需的工具调用被跳过,即使回复文本看起来没问题,评测也会失败 - 场景集——第一级子文件夹(仅一层)。
wayai run-eval每个会话恰好运行一个场景集,可以运行整个场景集,也可以通过可重复使用的--eval缩小到选定场景(并通过--runs指定选定场景的运行次数)——当改动只涉及大型场景集中的少数场景时,这是成本较低的循环 - 历程(
journeys/<slug>.yaml,平铺文件夹)——保存的成功路径对话记录,每个 Agent 回合都会生成一个衍生评测。构建广泛回归覆盖的默认方式:wayai eval journey capture <conversation_id>,然后运行wayai pull(同步服务器生成的步骤 ID) - 每次运行的
variables+runs: N——可靠性是一种分布,而非单次 1/1 样本;每次运行都会根据各自独立的行解析{{var(name)}} - 种子
fixture:——适用于任何会执行写入的评测:指定一个基础设施 fixture,平台会在会话期间租用该 fixture——获取时重置,释放时清理——让每次运行都从已知的基线开始,而不是沿用上一次运行的残留状态。一个预览基础设施一次只允许一个评测会话:第二次启动会以fixture_target_in_use(409)被拒绝,而不会获准破坏第一个会话;默认情况下,run-eval会等待此情况解除——对于fixture_seed_unavailable(409)也会如此,此时基础设施因自身写入背压而暂时拒绝租用 - 种子
initial_state:——在运行input之前,预先填充用户范围的 WayAI 状态(例如回头客记录、已保存的个人资料),以便测试依赖过往对话记忆的行为;与fixture:一样,每个会话相互隔离,并在会话结束后清理 - 指定客户
customer_contact_id:——指定场景的各次运行或历程的各个步骤所服务的联系人,让客户范围的工具集在评测中仅读取该客户的记录;仅在预览 hub 上受支持(references/evals.md) - 捕获——
wayai eval capture <conversation_id>会将生产环境对话的最后一轮冻结为场景 YAML - 呼叫评测(语音通话)——
wayai run-eval --call-mode和wayai eval call:references/evals.md
工具依赖型评测的良好实践:组合使用历程 + fixture: + variables,以便重复运行和并行运行;将 evaluator_instructions 表述为功能结果,而非原始调用次数(“成功预订一次”,而非“恰好调用一次 book_appointment”)——工具可能会暂时失败,而正确的 Agent 会重试。完整的 YAML 格式、种子连接设置、运行间隔,以及编写和解读原则:references/evals.md。
自动化
自动化会自行在中心启动工作:包含一个 触发器(schedule — 5 字段 cron 表达式 + 时区;在任务中心上也可以是 event — conversation.flagged 或 conversation.closed,每个事件创建一个任务,并将对话作为带围栏的数据交给任务;不会触发自动化自身的任务;且最多嵌套三层,避免自动化循环:references/automations.md — 属于此中心,或通过 source_hub 指定组织中的另一个生产中心,仅限生产环境,且其发布者必须能读取该中心的对话:references/automations.md — 或 webhook — 外部系统向自动化专属 URL 发送的签名请求:references/automations.md)、一个 目标(contact_list — 通过 list 指定的中心自有列表,或通过 org_list 指定的组织列表;在任务中心上也可以是 none),以及针对触发器触达的每个联系人的一个 操作:
send_message(仅限聊天中心)— 在whatsapp上发送 WhatsApp 消息模板,在email上发送text邮件(使用其连接;营销邮件会附带退订链接),或在app上发送textrun_agent— 一个agent(pilot或pilot_specialist)和由管理员编写的instructions。在聊天中心上,针对某个channel(whatsapp/instagram/email/app;除app外,每个渠道都需指定连接;whatsapp还需指定一个已获批准的模板,用于开启已关闭 24 小时窗口的对话):指定的 Agent 会在每个联系人的该渠道专属对话中,按照说明执行一轮并在对话中回复。在任务中心上,这是唯一可保存的操作,且不指定渠道:每次运行都会创建任务,每次运行一个任务(target: { type: none })或每个联系人一个任务;每个任务都没有关联人员,由指定的 Agent(pilot或pilot_specialist)按说明执行;联系人的记录会作为带围栏的数据传递给任务,不会放入说明中。references/automations.mdinstructions会按原文发送:其中的{{…}}占位符不会被填充(但它们在 Agent 自身的说明中有效)- Webhook 触发器(仅限任务中心):
trigger: { type: webhook, auth: hmac }— 每次请求都按基础的入站 webhook 签名方式签名(X-Data-Signature/-Timestamp/-Id,因此发布的 SDK 的signRequest可以为其签名);也可以使用auth: static_header,并通过header指定承载密钥的标头。每个获接受的请求都会创建一个任务,任务开头包含请求正文,并将其作为带围栏的数据置于说明之外。创建自动化时(通过应用或 API,在生产环境中由中心管理员操作)以及每次轮换时,密钥只会显示一次;推送或发布不会创建密钥。references/automations.md
联系人和组织列表是组织数据,而非中心配置:它们存放在组织的联系人簿中,由组织设置(Contacts 标签页)和组织 API(/api/contact-book)管理,绝不会放在 hub.yaml 中。自动化可以指定一个组织列表 — target: { type: contact_list, org_list: <list-name> } — 或一个中心自有列表 — target: { type: contact_list, list: <list-name> },这是联系人簿标签和范围标签的筛选条件,保存在 hub.yaml 的 contact_lists: 下 — 每次触发都会触达该列表中触发中心可见的成员。组织管理员,或持有覆盖整个组织的 contacts:write 权限的令牌,可以管理联系人簿;中心管理员可以查看其中心可见的联系人。联系人的可见范围(创建/导入时选择其范围标签或所有中心,并选择环境:默认为 production,因此预览中心只能看到 preview 和 all 联系人)、组织列表和 CSV 导入:references/automations.md。
- **缺失与空值:**没有
automations:(或contact_lists:)键时不会更改任何内容;[]会删除所有自动化(或 Hub 列表)。自动化所指向的 Hub 列表永远不会被删除;重命名列表时,也会重命名自动化中的引用(除非另一个列表占用了旧名称)。不再读取旧的outbound_schedules:键,以及被联系人簿取代的 Hub 联系人和列表区块 - 保存时绝不会查找组织列表(Hub
list除外:它必须是 Hub 中的某个列表):可以删除或重命名自动化所指定的组织列表;下次触发时会记录list_not_found并发出 Hub 警报。每次运行都会一次读取 100 个联系人的列表页面,因此联系人簿所容纳的任意大小的列表都能遍历到,每个联系人最多一次;运行会在联系人的页面加载到时显示这些联系人,暂停后会在下一页开始前停止 - **抑制规则:**联系人簿会保存要求不接收自动化消息的对象——电话号码、电子邮件或 Instagram ID,范围为
marketing或all;即使删除联系人,这些记录也会保留。每项自动化的purpose(默认为marketing,或operational)决定会应用哪些抑制规则:营销消息会跳过这两种范围,运营消息(如提醒)只会跳过all。管理员可在 Contacts 标签页或通过 API 添加和移除抑制规则;电子邮件的退订链接会写入all,而 WhatsApp 因对方停止接收营销消息而拒绝发送营销消息时,会写入marketing。references/automations.md - **触发时会触达哪些人:**Hub 屏蔽的联系人永远不会收到消息;联系人簿中的联系人条目会在 Hub 要求新联系人先获得许可时为其授权,因此不会发起访问请求,且其回复会发送给 Agent(如果其请求已在等待审批,则会获批并继续由团队管理;
run_agent会跳过团队管理的对话);在应用中,只有已关联 WayAI 账户且该账户已获得 Hub 访问权限的联系人会收到消息——自动化绝不会授予访问权限 - 在启用、未暂停且可运行时运行:
hub.yaml中的enabled:(或应用中的切换开关)会启用自动化——定时计划的下一次运行会进入队列,事件自动化会在事件发生时运行,Webhook 自动化会接受投递——预览和生产 Hub 均如此,但带有source_hub的事件自动化只会在生产环境中运行;在应用中暂停会停止自动化,发布会保留生产环境中的暂停状态。除暂停、恢复、立即运行和 Webhook 自动化的密钥轮换(由 Hub 管理员执行)外,只有通过发布才能更改生产环境。立即运行会触发一次 - **门控:**可选的
gate: { monitor: <agent name> }——基于决策模型的监视器会在每次运行开始前决定(trigger: automation_fire):运行、改用另一个 Agent 运行,或跳过;如果目标是联系人列表,则会在开始处理每位联系人之前逐一决定(trigger: automation_item):开始、改用另一个 Agent 开始,或跳过;门控失败或超时,则不会运行其所控制的内容。references/automations.md - **保存时拒绝并指出自动化名称的情况:**未知键、操作不使用的字段(例如任务 Hub 中的
channel或connection)、聊天 Hub 中的none目标、聊天 Hub 中的事件触发器或带列表目标的事件触发器、聊天 Hub 中的 Webhook 触发器、监视器不是决策模型上的automation_fire监视器(或联系人列表目标下的automation_item监视器)的门控,以及 Instagram 上的send_message(目前不可用)
Instagram 只能触达过去 24 小时内发过消息的联系人——承诺结果前,请检查每次触发会执行什么。结构、示例、参考资料、每次触发的行为、消息模板和限制:references/automations.md。
分析
每段对话都会连同来自五种来源的变量写入分析存储:
| 来源 | 路径 | 设置方 |
|---|---|---|
| 系统指标 | data.system.* | 平台 — 消息数、响应时间、时长、令牌(约 25 项指标) |
| Agent 定义的变量 | data.variables.* | conversation_evaluator / message_evaluator Agent 中声明的 evaluation_variables |
| 元数据 | data.meta.* | 平台 — subject、kanban_status、hub_type |
| 事后标注 | data.annotations.* | wayai conversations <id> annotate --set key=value — 对话结束后记录实际业务结果(已购买、已流失);用于对照预测与实际情况 |
| 评估分数 | data.eval_scores.* | 仅评估运行(is_eval = true 的行 — 不纳入生产分析) |
对话行是一个数据粒度;第二张表 message 会将每段对话的开销拆分到各条消息(令牌、美元成本、操作),以便按模型、Agent 和凭证分析成本。
可使用 wayai analytics(汇总和各变量聚合;--metric、--filter、--period)、wayai analytics query(结构化查询:多变量、group_by、相关性)、wayai analytics sql(对 conversation 和 message 执行原始 SQL — 成本分析入口),或 wayai evals sql(对评估行执行相同的 SQL)。如何定义优质变量,参见评估 Agent(roles-and-settings.md → Evaluation Variables);筛选、聚合、成本查询和工作流,参见:references/analytics.md。
团队、用户与访问权限
人员实体由 UI 管理(Hub → Users 选项卡:/settings/organizations/<orgId>/hubs/<hubId>/users),不在 YAML 中配置:
- Hub User — AI 对话的最终用户(客户/潜在客户/员工)。使用
/chat(移动应用中的 Chat 选项卡);他们可在其中执行的操作:references/using-the-app.md - Hub Team User — 在
/support中处理对话的支持团队成员(收件箱、认领、转接、关闭、看板:references/support-inbox.md);成员归入 Teams(例如 “Tier 2 Support”),transfer_to_team按名称指定目标团队 — 未知的target会在运行时失败 - Hub Admin — 拥有完整的 Hub 配置访问权限。Org Owner/Admin — 组织级别的管理权限(计费、凭证、Hub)。访问权限按级别区分,不会继承(组织管理员不会自动成为 Hub 管理员)
- 联系人访问控制 — 当
non_app_permission: require_permission时,未知渠道的联系人会处于pending状态(收到本地化自动回复,可通过access_request_message覆盖),直到由access_approval_role中指定角色的成员批准或屏蔽
Hub 环境
| 环境 | 描述 |
|---|---|
preview | 默认环境。可编辑的工作区,用于配置和测试 |
production | 只读。承载线上流量。更改通过发布/同步从 preview 流转而来 |
生命周期:
- 新建 hub 时会以
preview环境启动,可自由编辑。创建时,wayai create --label <l>(或自动创建时使用wayai push --label <l>)会为首个 preview 命名。仅当 API 令牌的授权范围涵盖该组织在 preview 环境中的每个 hub 的hub:write权限时,才会创建 hub;否则返回403。创建 hub 时,wayai create/wayai push不会发送任何标签,因此受标签限制的令牌无法通过 CLI 创建 hub——请使用组织范围的令牌或 UI - 发布(CLI
wayai publish,或 UI)——首次晋级会从 preview 克隆并创建一个productionhub - 同步(CLI
wayai publish/ 别名wayai sync,或 UI)——将后续的 preview 更改推送到关联的 production。该命令会自动检测是首次发布还是同步;默认会先确认(显示 preview→production 差异),使用-y可跳过提示。它会晋级已推送的 preview 状态,因此请先执行wayai push - 复制 Preview(CLI
wayai replicate [hub] --label <l>或 UI)——从 preview 或 production 创建一个新的同级 preview,用于实验 - 重新标记(CLI
wayai relabel <label>/--clear,或 UI)——设置/清除 preview 的preview_label(用于区分同级项)。不能通过hub.yaml+ push 编辑——它由服务端管理
Production 为只读——所有配置变更都通过 preview 流转。多个 preview 可以关联同一个 production(多对一)。仅在 production 上强制频道唯一性——preview 可以与其 production 共享电话/电子邮件/SID。
发布和同步会写入 production hub,因此 API 令牌(wayai login --token)只有在其授权范围涵盖该 hub 的 hub:write 权限时才能发布。preview 发布后,wayai publish 首先会读取该 hub,以显示 preview→production 差异,因此令牌还需要该 hub 的 hub:read 权限。仅限 preview(按 hub 限制或限制到 preview 环境)的令牌会被拒绝,并返回 403。首次发布会创建 production hub,因此令牌需要访问该组织在 production 中的每个 hub(如果令牌受标签限制,还需要访问 preview 的标签)。已登录用户仍按原方式发布。
WhatsApp/Instagram/Telegram 频道可以在发布前于 preview 上测试——使用 #test CODE 认领码注册测试者(参见 references/connections.md → Channel → “Testing a channel on a preview before publishing”)。
只有 preview hub 可以编辑。wayai pull 也会将关联的 production hub 写入一个只读镜像文件夹(使用纯 slug 名称——不带 --<label> 后缀——并在 hub.yaml 中添加标记注释),以便在 preview 旁浏览线上 production 配置;wayai push 会拒绝该文件夹,且自动选择时会将其排除。使用 wayai diff --production 可查看简洁的 preview 与 production 差异。
Hub 设置
| 设置 | 值 | 默认值 | 描述 |
|---|---|---|---|
non_app_permission | everyone、require_permission、not_allowed | everyone | 谁可以通过外部渠道访问 Hub |
timezone | IANA 时区 | — | 用于安排时间和显示 |
language | en、pt、es | en | Hub 发送的文本所用语言(例如,使用 require_permission 的渠道发送的待审批访问通知) |
access_approval_role | admin、team | admin | 谁可以批准或屏蔽待处理联系人:仅限 Hub 管理员,或也包括支持团队成员 |
access_request_message | 字符串 | — | 可选,用于覆盖“您的访问正在等待审批”自动回复的文本(否则会根据 language 使用本地化默认文本) |
display_names | en / pt / es → 字符串(≤120 个字符)的映射 | — | 按应用语言设置 Hub 终端用户看到的名称。团队和管理员视图仍显示 name |
welcome_messages | en / pt / es → 字符串(≤1000 个字符)的映射 | — | 按应用语言设置终端用户发送首条消息前看到的问候语 |
starter_questions | en / pt / es → 最多包含 4 个字符串(每个 ≤120 个字符)的列表的映射 | — | 按应用语言设置终端用户可点击发送的推荐首条消息 |
auto_close_inactive_days | 1–180 | 7 | 无活动(用户或团队未发送消息)的天数,超过后对话将被强制关闭。每个 Hub 都有此设置 |
conversation_retention_days | 1–30 | 7 | 已结束对话的 DO 在清理前保持可用于事后 annotate 的天数,以及评估调用页面(evals.md → 调用评估)的保留天数(归档仍在关闭时进行) |
ended_index_retention_days | 1–730 | 365 | 已结束对话在 Hub 索引中保留的天数。此值决定“已结束”选项卡的范围,以及 {{previous_conversations(N)}} 能追溯的时间范围 |
eval_retention_days | 0–3650,或 null | 平台默认值(90) | 已完成的评估会话(其运行记录、结果和评估对话)在弃用前保留的天数。0 表示永久保留会话。省略此字段会保留当前值不变 — 写入 eval_retention_days: null 可清除覆盖值并恢复平台默认值。弃用会永久删除转录记录 — Analytics 中的评估分数仍会保留 |
end_user_daily_message_limit | 1–10000,或 null | 不限 | 终端用户在 24 小时内可通过 WayAI 应用向 Hub 发送的消息数上限,计时从其首条计入的消息开始。超过上限后,直到计时窗口结束前,其消息都会被拒绝,应用也会告知原因。仅统计终端用户 — 不统计团队消息、组织成员或 Hub 管理员的消息。其他渠道不受限制。省略此字段会保留当前值不变;设为 null 可移除限制 |
终端用户展示(display_names、welcome_messages、starter_questions):每位查看者会看到与其应用语言对应的条目;若没有,则使用 Hub 的 language;再没有,则使用映射中任意语言的条目。因此,请为终端用户使用的每种语言都设置内容,否则缺失的语言会显示其他语言的条目;仅当 display_names 为空时,名称才会回退为 name。不接受 en、pt 和 es 以外的区域设置。省略映射会保留其不变;null 或 {} 会清除映射。这些设置只会更改终端用户在应用中看到的内容:它们不会翻译 Agent 的指令、name 和 ai_* 通知。Web 和移动应用会在终端用户的聊天列表(搜索可找到任一名称)和对话线程标题中显示名称,并在尚无消息的对话线程中显示欢迎语和推荐问题;点击问题会将其作为首条消息发送。支持、Kanban 以及所有团队或管理员视图仍显示 name。Hub 管理员也可以在 Web 应用的 Hub 设置中按语言编辑这三项内容(概览 → 终端用户展示)。
首次设置(冷启动)
用户的入口是 wayai.pro,其引导部分提供安装命令和示例提示词。技能加载后(此处),本节将引导完成从“技能已加载”到“中心已能响应测试消息”的所有步骤。Agent 必须仅根据本节自行完成初始化——回访用户(第二个中心、新项目)可跳过此页面。
始终先运行 wayai status --json。 它会返回单个状态快照。根据结果选择后续步骤;每完成一步都重新运行以确认进度,再继续下一步(幂等)。
表述模板(逐字使用)
- Agent 操作 — 先用一行说明,再执行,然后用一行确认:
- “正在安装 CLI……” → 运行命令 → “完成 — 已安装
wayai 2.4.1。”
- “正在安装 CLI……” → 运行命令 → “完成 — 已安装
- 交接给用户 — 恰好一个 URL、一个操作、一条返回信号:
- “打开
<URL>。执行<一个操作>。完成后告诉我。”
- “打开
状态机
| # | 检测条件(来自 status --json 或环境变量) | 操作 |
|---|---|---|
| 1 | 缺少 CLI(未找到 wayai --version) | Agent 运行 npm i -g @wayai/cli@latest。 |
| 1b | 项目根目录下没有安装任何 harness 技能(<root>/.claude/skills/wayai/SKILL.md、<root>/.opencode/skills/wayai/SKILL.md、<root>/.agents/skills/wayai/SKILL.md 均不存在,其中 <root> 是 git rev-parse --show-toplevel 的结果;若当前目录不在 git 仓库中,则为当前工作目录) | 如果你是 Claude Code,请先运行 mkdir -p <root>/.claude——只有 .claude/ 已存在时,skills 安装程序才会为 Claude Code 创建 .claude/skills/wayai 链接;否则会跳过且不作提示,但仍会打印 "symlinked: Claude Code"。然后从 <root> 运行 npx skills add wayai-pro/wayai-skill -y。完成后,验证你自己的 harness对应路径是否可解析(Claude Code → <root>/.claude/skills/wayai/SKILL.md,沿符号链接解析;其他 harness → <root>/.agents/skills/wayai/SKILL.md)。如果可解析,则退出(harness 会在下一轮加载技能)。如果不可解析,但 <root>/.agents/skills/wayai/SKILL.md 存在,则自行修复:运行 mkdir -p <root>/.claude/skills && ln -sfn ../../.agents/skills/wayai <root>/.claude/skills/wayai,然后再次验证。如果仍然没有,则显示安装错误并停止——不要静默退出(否则重新进入时会陷入循环)。 |
| 1c | skill.installed: true,已设置 skill.latest,且 skill.latest 比 skill.version 新(CLI 的 nightly 检查会填充 skill.latest) | Agent 从 <root> 运行 npx skills add wayai-pro/wayai-skill -y,就地更新安装,然后退出(更新后的技能会在下一轮加载)。如果安装失败,向用户显示错误,并继续使用现有技能。 |
| 2 | auth.logged_in: false | Agent 运行 wayai login(打开浏览器)。交接给用户:"打开刚才打开的页面。登录或注册。完成后告诉我。" |
| 3 | auth.logged_in: true,orgs: [] | 询问一次:"组织要叫什么名字?(通常是公司名称)"。然后 Agent 运行 wayai org create "<name>",并重新运行 status --json 以获取新组织。(仅当 CLI 创建失败时使用手动备用方式:打开 https://app.wayai.pro/settings/organizations/new。) |
| 3b | git rev-parse --show-toplevel 失败(当前工作目录不在 git 仓库中) | CLI 需要 git 来检测工作区。采取操作前,显示解析出的当前工作目录,并向用户确认——交接内容:"我将在 <cwd> 初始化 git 仓库。请确认,或选择其他文件夹。"这样可以避免意外在 ~ 或其他非预期目录中初始化仓库。确认后,Agent 在当前工作目录运行 git init。然后检查 git config --global user.name 和 git config --global user.email;如果任一为空,则向用户询问一次姓名和电子邮箱,并运行 git config --global user.name "<name>" / git config --global user.email "<email>"。引导流程不需要 GitHub 远程仓库——只有用户想要 GitOps/CI 工作流时,才在后续设置。 |
| 4 | workspace.scoped: false 且 repo_scope_blocker: null | Agent 运行 wayai init --org <active_org.id>——将组织绑定写入 wayai-ws/wayai.yaml,这是该仓库唯一提交的工作区清单文件。 |
| 4b | workspace.scoped: false 且已设置 repo_scope_blocker | 不要运行 wayai init——它会重写 wayai-ws/wayai.yaml,无法修复两个配置文件内容不一致的仓库。对于 kind: "conflict",告知用户两个组织 ID,并询问此仓库属于哪一个组织,然后删除或更正根目录下的 .wayai.yaml。对于 kind: "invalid",显示指定文件及其 detail,并请用户修复。之后重新运行 status --json。 |
| 5 | 工作区已限定范围,但尚不清楚 hub 的目标 | 交接给用户:"这个 hub 应该做什么?请描述目标、使用者以及主要用例。" |
| 6 | 所选提供方缺少 LLM 凭证 | 交接给用户:"请在此处粘贴你的 OpenAI/Anthropic/Google API 密钥。"然后 Agent 运行 wayai create-credential --name <name> --type "Bearer Token" --stdin。 |
| 7 | hub 需要 OAuth 连接(WhatsApp / Instagram / MCP OAuth) | 执行 OAuth 连接交接(连接与凭证 → OAuth 连接交接):发送该连接器的完整路径连接深层链接,等待完成,然后运行 wayai pull -y。之后任何时候需要 OAuth 连接,也适用相同的交接方式,不仅限于此处。 |
| 8 | 已满足前置条件 | 阅读一次 references/canonical-example/README.md,了解端到端的连接配置;然后根据用户的描述生成 wayai-ws/hubs/<hub>/hub.yaml + agents/*.yaml + agents/*.md(各部分的具体格式参见下方对应领域的参考资料);接着运行 wayai create -y 创建并推送新 hub(如果工作区中只有这个新文件夹,wayai push -y 也会自动创建)。 |
| 9 | 推送成功 | Agent 运行 wayai send-message "Hi" 并显示响应。交接给用户:"要优化、添加工具,还是发布?" |
| 10 | 用户确认发布 | Agent 运行 wayai publish——显示预览版→生产版的差异,然后确认(或运行 wayai publish -y 跳过提示)。首次发布会将预览版克隆为新的生产 hub;之后的运行会进行同步。仅限付费套餐——如果 CLI 报告发布需要付费套餐,则使用手动备用方式:打开下方的发布深层链接,在 UI 中升级并发布。 |
Deeplink(规范 URL — 绝不是面包屑)
| 状态 | URL |
|---|---|
| 3(创建组织 — 手动备用方案) | https://app.wayai.pro/settings/organizations/new |
| 6(预填凭据) | https://app.wayai.pro/settings/organizations/<org_id>/credentials?type=bearer&name=<key-name>&prefill=true |
| 7(OAuth 连接) | https://app.wayai.pro/settings/organizations/<org_id>/hubs/<hub_id>/connections?connector=<whatsapp|instagram|mcp-server> |
| 10(发布 — 手动备用方案) | https://app.wayai.pro/settings/organizations/<org_id>/hubs/<hub_id>/overview?action=publish |
规则
- 检测,不要假设 — 每个步骤都从全新的
wayai status --json开始。 - Agent 操作要提供一行回执;移交给用户时要提供一个 URL、一个操作和一个返回信号。
- 绝不要编造上表之外的 URL。绝不要指示用户“前往 Settings → …”——始终使用 deeplink。其他 URL 请参阅
references/navigation.md。 - 在 hub 范围界定期间(状态 5),一次只问一个问题:先目标,然后渠道,最后是 LLM 提供商。
- 绝不要自动提交 onboarding 期间创建的任何内容——显示
git diff,并等待用户批准后再进行任何提交。
工作流
现有 hub
- 更新 CLI —
wayai update(执行任何操作前始终运行;如果尚未安装 CLI,则使用npm i -g @wayai/cli@latest引导安装) - 技能过时则更新 — 运行
wayai status --json;如果已设置skill.latest且其版本高于skill.version,则运行npx skills add wayai-pro/wayai-skill -y并退出(刷新后的技能会在下一轮加载)。否则继续。(冷启动 onboarding 也会执行与状态机第 1c 行相同的检查。) - 拉取 —
wayai pull -y(从平台同步本地文件;捕获平台外的变更) - 读取上下文 — 读取此 hub 的
wayai-ws/hubs/<hub>/AGENTS.md说明(用途、决策、进行中的工作);如果还要处理某个 base,也要读取wayai-ws/bases/<base>/AGENTS.md。能够读取 AGENTS.md 的运行环境(Claude Code、Codex、Cursor、OpenCode、Aider)会原生自动加载AGENTS.md,但不要依赖这一点——请参阅Hub 文件夹记忆。顺便清理过时的根目录引导文件——请参阅移除旧的根目录AGENTS.md - 编辑 — 修改
hub.yaml、agents/*.yaml、agents/*.md - 推送 —
wayai push -y(应用到预览 hub;自动将服务器分配的 ID 拉取回来) - 测试 —
wayai send-message "Hello" - 审查 — 运行
git diff,请用户确认。**绝不要自动提交。**由用户提交并推送到main - 上线 — 准备就绪后运行
wayai publish(或使用平台 UI):显示预览版→生产版差异并确认,然后首次发布(克隆预览版→新的生产 hub),或同步后续变更。先运行push——它会提升已推送的预览状态,而不是尚未推送的本地编辑
新建 hub(从头开始)
- 凭据 —
wayai create-credential --name "openai-key" --type "Bearer Token"(每个组织、每项凭据只需执行一次) - 初始化 —
wayai init(交互式)或wayai init --org <uuid> - 创建文件 —
wayai-ws/hubs/<hub>/hub.yaml+agents/*.yaml+agents/*.md - 创建 —
wayai create -y会创建 hub、非 OAuth 连接,并应用所有配置(自动绑定工作树)。如果工作区中有多个 hub 文件夹,则使用create <folder>。(wayai push -y在解析到单个新文件夹时也会自动创建;在多 hub 工作区中则需要--hub,因此create是明确无歧义的动词。) - 测试 —
wayai send-message "Hello"
hub 创建后,按照现有 hub 工作流操作。
Hub 文件夹记忆
wayai-ws/hubs/<hub>/AGENTS.md 是此 hub 的专属记忆,用于记录配置文件(hub.yaml、agents/)无法涵盖的上下文信息:用途、关键决策及其原因、正在进行的工作、仅适用于此处的业务规则、术语和集成注意事项。每次处理与 hub 相关的任务时,都要先阅读此文件。如果文件夹中没有 AGENTS.md,wayai pull/push 会在确认文件不存在后创建一个占位文件。支持读取 AGENTS.md 的工具(Claude Code、Codex、Cursor、OpenCode、Aider)会在 Agent 的当前工作目录位于 hub 文件夹内时自动加载该文件;但 Claude Code 是否会这样做,取决于其版本、设置,以及该文件夹中或其上层的 CLAUDE.md 系列文件(Claude Code 文档)。因此不要依赖自动加载:如果 hub 的 AGENTS.md 尚未包含在已加载的指令中,请自行阅读。较早版本的 CLI 还会在旁边创建一个只有一行 @AGENTS.md 的 CLAUDE.md;它不会造成影响,请保留。
主动维护此文件:
- 完成重大更改后(新增 Agent、新工具、更新业务规则),更新
AGENTS.md,让后续会话能继承这些上下文 - 如果 hub 文件夹没有
AGENTS.md(或只有自动创建的占位文件),请根据已知信息补充内容,包括用途、当前 Agent 和近期决策,并请用户确认或补充 - 重点记录决策背后的原因,以及此 hub 的独特之处。不要重述平台机制——这些内容由此技能记录
- 可在
## Build plan部分记录商定的范围——使用这个准确的标题,其下可选填一行Goal: <一句话>,然后添加 GitHub 任务列表项(- [ ]/- [x]),最多嵌套一层。控制在约 30 项以内;超过后,请拆分为多个阶段,并将已完成的阶段归档到列表上方的正文中。完成后及时勾选——只有推送后且已正常运行,任务才算完成,而不是 YAML 文件存在就算完成。与AGENTS.md的其他内容一样,此部分永远不会同步到平台 - Bases 同样适用。 如果你也在处理一个 base,请将设置无法涵盖的上下文记录在
wayai-ws/bases/<base-id>/下 base 文件夹的AGENTS.md中(如果文件不存在,请创建)
超出部分移至 wayai-ws/hubs/<hub>/references/:
- 当
AGENTS.md超过约 200 行或开始混杂多个主题时,将更深入的内容拆分到wayai-ws/hubs/<hub>/references/下的专门文件中 - 示例:
references/business-rules.md、references/integrations.md、references/glossary.md、references/<api-name>-spec.md、references/<persona>-tone.md - 保留
AGENTS.md作为始终加载的入口,并简短指向每个参考文件,例如:“详细定价规则:references/pricing-rules.md” - hub 文件夹中的
references/不会同步到平台,仅用于提供 Agent 上下文,与AGENTS.md一样
弃用旧的根目录 AGENTS.md
旧版 CLI 会在仓库根目录生成 AGENTS.md(以及一个包含 @AGENTS.md 的 CLAUDE.md)作为会话引导:检查更新,然后加载此技能。现在已没有任何内容会写入或刷新它,因此其中的信息会冻结在生成它的版本,而实际流程却不断演进——如果副本仍然写着本技能已更改的安装命令或启动步骤,就会悄悄把你引向错误的流程。它的内容现在也完全多余:其中的所有内容都已在此说明。如果你在仍有该文件的仓库中工作,请首次工作时将其弃用——这仅针对仓库根目录;hub 和 base 文件夹中的 AGENTS.md 是记忆文件,必须保留。
识别方法:生成的文件标题为 # Working with WayAI,正文全部是“检查更新,然后加载 WayAI 技能”的引导,以及几行与用户沟通的说明——没有任何项目专属内容。(较旧版本的副本可能改为描述要安装和加载两个技能;WayAI 和 Data 两个界面已合并为此技能,因此那种副本就更加过时了。)然后:
首先,确认你是否是通过该文件找到这里的。 不同的运行环境有所不同,这决定了该采取什么操作:
-
你从自己的技能目录加载技能(Claude Code →
.claude/skills/,OpenCode →.opencode/skills/)→ 根目录文件对你不起作用。删除它;如果CLAUDE.md只是单行的@AGENTS.md引用文件,也一并删除。 -
你会自动加载
AGENTS.md(Codex、Cursor、Aider)→ 根目录文件可能是指引你找到此技能的唯一线索,删除它会导致下次会话找不到入口。保留该文件并将过时的引导替换为指向此技能的说明,这样内容就不会冻结,同时也保留了跳转入口:# Working with WayAI Load the WayAI skill at the start of every session, before anything else: `.agents/skills/wayai/SKILL.md`. It holds the real instructions.
无论哪种情况,如果文件还包含你自己的笔记,都要保留——只替换或删除生成的引导部分。完全由你自己编写的根目录 AGENTS.md 并非 CLI 创建的;不要动它。
引导中原有的所有内容现在都在此技能中:更新规范见 Agent 指南,操作流程见 工作流 → 现有 hub。
常用 CLI 命令
wayai update # Update CLI (run before any operation)
wayai login # OAuth — or `wayai login --token` for headless/CI
wayai logout # Sign out and clear stored credentials
wayai whoami # Show the authenticated identity
wayai org create # Create a new organization (you become its owner): `wayai org create "<name>"` [--region <r>] [--json]
wayai org pull # Org-as-code: fetch org-level shared skills → wayai-ws/org/
wayai org push # Org-as-code: apply local org skills to the platform (fans out to linked hubs); `wayai org diff` previews
wayai create-credential # Create org credential (--name, --type "API Key"|"Bearer Token"|"Basic Auth", --org, --stdin)
wayai update-credential # Rotate/edit an org credential (--name <cred>; --stdin/--secret rotates the secret, --rename, --description, --tag, --environment)
wayai set-connection-credential # Set a connection's credential directly — --connection <name> + either --org-credential <name> (link) or --field <f> --stdin (raw secret: unlinks only that field's org credential). Works on preview + production (the sanctioned production-credential write)
wayai init # Scope this repo to an org in wayai-ws/wayai.yaml (interactive — creates an org inline if you have none); --org <uuid> to skip prompt
wayai migrate # Move a legacy workspace/ + root org/ layout to wayai-ws/, and copy a root .wayai.yaml org binding into wayai-ws/wayai.yaml (the root file is KEPT — older CLIs still need it)
wayai pull # Pull hub config from platform (-y skips confirmation; auto-binds worktree on first pull). Also writes the linked production hub as a read-only mirror folder
wayai push # Push local changes (-y skips confirmation; auto-pulls IDs back). Auto-creates a lone new folder; a multi-hub workspace needs --hub or `wayai create`
# `pull`/`push` are ONE verb each, routing by workspace subtree: `hubs/<hub>` (above), `bases/<base>` (the Data surface)
# or `communities/<community>` (references/communities.md) — a community only by the flag, a positional or its folder as cwd.
# The target resolves in this order: the `--hub`/`--base`/`--community` flag → a positional → the folder you are cd'd into →
# `wayai-ws/wayai.yaml`'s `default_hub`/`default_base` → the sole folder across the hubs and bases subtrees.
# So in a workspace holding BOTH a hub folder and a base folder, a bare `wayai pull` is refused as ambiguous.
# Name the subtree — `wayai pull bases/crm`, `wayai push hubs/support` — or declare ONE default in wayai-ws/wayai.yaml.
# An invocation naming a target in BOTH subtrees is refused, never merged; run the two it prints, one at a time.
wayai pull bases/<base> # Pull a base's config into wayai-ws/bases/<base>/ (-y skips the overwrite confirm; auto-binds; mirrors a production origin read-only)
wayai push bases/<base> # Push a base folder to its PREVIEW base (--dry-run to stop after the diff; --prune to apply removals). Production is `wayai bases promote`, never push
wayai create [folder] # Explicitly create a new hub from an idless folder, then push (--label names the preview). The discoverable verb when a workspace has more than one hub folder
wayai diff # Dry-run diff of local files vs preview (read-only); --production diffs vs the linked production hub
wayai replicate [hub] # Clone a hub (preview or production) into a new sibling preview; --label <l> names it. Pulls the new preview into its own folder
wayai relabel <label> # Set a preview hub's label (--clear removes it; --hub to target). Renames the local folder. The server-owned way to change preview_label
wayai publish # Promote the preview to production (alias: wayai sync). Auto-detects first-publish (clones preview → new production) vs sync (pushes changes to the linked production); shows the preview→production diff and confirms (-y skips). Paid plans only. `wayai push` first — promotes the pushed preview state
wayai use <selector> # Scope this worktree to a hub, base or community (UUID, folder name, hubs/<n>, bases/<n>, communities/<n>, --hub/--base/--community). Replaces that axis; `--add` widens it instead
wayai unbind [<sel>] # Drop one entry from the worktree scope; bare, it clears the whole scope (every axis)
wayai send-message # Test message to a hub (preview or production). -c <id> continues a conversation
# `-f, --file <path>` attaches a file (repeatable, max 20, ~7 MB/request) delivered exactly as a real channel does — this is how image/document behaviour gets exercised in the dev loop. Message text is optional when a file is attached (an attachment-only send mirrors a photo with no caption). Images reach the model as a signed URL, not base64
wayai alerts # Active connection/credential alerts for a hub (Status & Notices). RUN THIS FIRST when a hub misbehaves (audio/TTS not delivered, agent not replying, a tool failing) — an invalid/expired provider key shows as `connection_auth` (usually 401) here instead of forcing a guess from code. --hub <uuid|name>, --json
wayai conversations # List or inspect conversations (default text view omits message_id — use --json or `observability` to discover ids)
# `--status <agent|team|ended>` combines with `--period 7d` / `--from` / `--to`, which bound LAST ACTIVITY: `--status team --to <date>` is the idle human-queue check ("waiting on a person, nothing since <date>"). Without `--status` AND without `--org`/`--all`, a bare `--period`/`--from`/`--to` reads the analytics history instead, which bounds conversation START and covers ended conversations only
# `--org <organization_id>` / `--all` list across the hubs `wayai list` enumerates plus the production hubs those name as parents — one command instead of a loop. These always read the live listing (open + ended, windowed on LAST ACTIVITY), with or without `--status`. A production PARENT you cannot read is named as skipped and does not fail the run. A production hub whose PREVIEW you cannot see is not enumerable anywhere, so it is NOT covered and NOT reported at all — reach it with `--hub <id>`. `--limit`/`--offset` are per hub; a hub in scope that refuses is named and the command exits non-zero rather than reporting a smaller queue, and an empty scope is reported as such, never as an empty queue
# `wayai conversations <id> observability` — list LLM turns with message_id, latency, tool_calls (assistant turns only)
# `wayai conversations <id> observability --message-id <id>` — full record for one turn (prompt, completion, tool calls, tokens; --json for raw)
# `wayai conversations <id> annotate --set key=value [--type numeric|categorical|text]` — set a post-hoc business outcome (e.g. customer_purchased=true) on an ended conversation as an analytics dimension; repeat --set for multiple keys (needs the hub within its conversation_retention_days window)
wayai delete-history # Clear conversation history (testing). Full history (no --conversation-id) ALSO clears the user's user-scoped hub state, so the next send-message is a true cold-open; --conversation-id <id> deletes just one conversation and never touches state
wayai sync-skills # Sync skills to provider connections; --connection-id <uuid> to scope
wayai sync-mcp # Re-discover an MCP or Base Toolset connection's tools (refresh stale schemas); --connection <name|uuid>; --check reports drift read-only (CI, exit 1 on drift)
wayai analytics # Summary + per-variable aggregates; --metric, --filter, --period, --json
wayai analytics query # Structured ClickHouse query (multi-variable, group_by, correlations)
wayai analytics sql # Raw single-SELECT SQL over `conversation` (one row per conversation) and `message` (per-message tokens/cost/operations — the surface for cost analysis); --schema prints both catalogs + the message-grain rules (`data.*` paths need `toFloat64OrNull(toString(...))` for numerics, `toString(...)` for grouping); --limit, --json
wayai evals # List eval scenarios for the hub (--enabled / --disabled)
wayai evals sql # Raw single-SELECT SQL over the hub's eval result rows ("SELECT …"; --schema prints the column + eval-score-path catalog; --limit, --json)
wayai run-eval # Run a scenario set's enabled evals (sole set by default; --set to pick on multi-set hubs; repeatable --eval <name> runs ONLY those scenarios and --runs 2,6 only those repetitions of one; --pacing conservative|balanced|fast|<ms> to throttle run dispatch; --call-mode runs every turn the way a live voice call runs it; waits inside --timeout for a fixture held by another session or for transient base write backpressure — --no-queue fails fast and --no-wait implies it; exits 1 if --timeout expires with the session still running)
wayai eval-results # Inspect eval results (--session <id> or --eval <name>; --runs for per-run detail, --json for raw)
wayai eval capture # Capture production conversation as eval YAML (<conversation_id> [--set <name>])
wayai eval journey capture # Capture a conversation's FULL transcript as a journey (<conversation_id> [--name <n>]); then `wayai pull` to sync it to journeys/<slug>.yaml
wayai eval session stop # Cancel a running eval session (<session_id>) — recovery when a run-eval died without cancelling its own session
wayai eval session delete # Delete an eval session + its run history (<session_id>, or --all for every session on the hub; -y to skip confirm)
wayai eval call # Place scored voice calls for a journey whose responder is the pilot_voice agent (--journey <name|id>, --runs, --clips <dir> or OPENAI_API_KEY, cost caps); needs `npm install -g @roamhq/[email protected]` once — see references/evals.md
# Journeys are hub-as-code: edit journeys/<slug>.yaml and `wayai push` (pull after first create to sync step ids)
wayai list # List organizations and hubs
wayai communities # An organization's communities (owners and admins; browser `wayai login` only): list, join-link get|rotate|off <community>, stats <community>, access list|add|remove <community> [<email>…] (an invite-only community's access list; remove takes out the members the email admitted); --org, --json, -y. See references/communities.md
wayai contacts # A contact's customer record in a base (organization admins; browser `wayai login` only): link-customer <contact_id> --base <base_id> --record <record_id>, unlink-customer <contact_id> --base <base_id>; --org, --json. See references/bases/toolsets.md#linking-a-contact-to-its-customer-record
wayai pull communities/<community_id|folder> # A community's settings, rules, join link state, rooms and courses as files (named explicitly, never by a bare pull); push applies them to the LIVE community (asks first; --dry-run, --theirs on pull)
wayai status # Show workspace status
wayai report create # Create platform bug report (--title, --description, --hub, --conversation, --error). With --hub, auto-attaches the hub's active alerts so triage sees a credential/connection cause up front — check `wayai alerts` yourself first, it's often not a platform bug
wayai report edit # Amend your own pending report (<id> --title/--description/--error/--steps/--context)
wayai report list # List your reports (newest first; --status <s>, --json)
wayai report get # Show a report's status + message thread (<id>, --json)
wayai report accept # Accept a shipped fix (<id>) → addressed
wayai report contest # Contest a shipped fix or a dismissal (<id> --reason "...") → back to triage
# Bases — the Data surface. A base is org-level and a separate entity from a hub.
# `use`/`unbind` are local (this worktree's scope file) and DEPRECATED — prefer
# `wayai use bases/<id>` / `wayai unbind bases/<id>`; every other command below
# reaches the platform. Full grammar: references/bases/.
wayai bases list # List bases (--tag to filter)
wayai bases get <id> # Show one base
wayai bases create <id> --name "<name>" # Create (--environment preview|production)
wayai bases update <id> --name/--tags/--timezone/--settings/--integrations
wayai bases rename <id> --name "<name>" # Display name only — the id/slug is immutable
wayai bases tag <id> --tags a,b # Replaces the existing tags; names must exist as organization tags
wayai bases delete <id> # Tombstone; --purge (preview only) destroys storage
wayai bases create-preview <origin-id> --name "<name>" # Clone config into a new preview
wayai bases list-previews <origin-id>
wayai bases promote <production-id> --from <preview-id> # NOT `wayai publish`, which promotes a HUB
wayai bases rollback <production-id> --promotion <id>
wayai bases promotions <production-id>
wayai bases use <base> # Deprecated alias of `wayai use bases/<id>` (see Worktree scope)
wayai bases unbind # Deprecated alias — clears only the base axis of the worktree scope
wayai bases tokens|secrets|sql|import|batch|providers ... # namespaced — each names a concept WayAI already owns
# Everything INSIDE a base is its own top-level namespace, each taking --base <id>:
wayai records | record-types | relationships | relationship-types | query-relationships
wayai files | file-types | attachments | toolsets | actions | triggers | inbound-webhooks | seed
wayai files pull|push <file_type> --base <id> [--folder <path>] # A file type's files as a local folder (knowledge as code). DATA, not config: writes any base, production included. Push shows the diff; a file changed, deleted or created on the base since your pull is a conflict, not written (a new file is sent create-only — references/bases/files.md)
wayai knowledge refresh-preview --org <id> --base <knowledge base> # Copy the knowledge base's production files into its preview, after creating it and whenever it should be current again (references/bases/files.md)
wayai bases --help(以及 wayai <namespace> --help)会打印完整的命令树;上述所有命令的语法都在 references/bases/ 中。需要牢记的两个命令区别:wayai use/wayai unbind 会维护一个涵盖 hub、base 和社区的工作树作用域(由选择器决定具体对象——wayai use bases/crm 与 wayai use <hub-uuid>),因此 wayai bases use/wayai bases unbind 已弃用,是仅针对 base 轴的别名;而 wayai publish 用于发布 hub,wayai bases promote 用于发布 base。Hub 和 base 是不同的实体,绝不能互相替代。
跟进你提交的报告。 分类处理升级问题并发布修复后,你的报告会变为 shipped 状态——你会收到一封电子邮件,且 wayai login/wayai status 会提醒你一次(也可以通过 wayai report list --status shipped 查找)。查看 wayai report get <id>(状态和处理者在线程中的备注),然后如果有效就执行 accept,如果无效就执行 contest --reason "..."。如果你认为某个已 dismissed 的报告确实成立,也可以执行 contest——报告会重新进入分类处理流程。
异议次数有限(有次数上限,且分类处理人员可能会将驳回标记为最终结论);超过限制后,请联系支持团队。
大多数命令都支持 --hub <uuid|folder>,可在 wayai-ws/hubs/ 中有多个 hub 时消除歧义。
工作树范围
每个 Git 检出(主工作树或关联工作树)都有一个范围:一组中心、一组基础项和一组社区,保存在 <git-dir>/wayai-scope 文件中(每个检出各自独有,绝不纳入版本控制)。
hubs: [11111111-1111-1111-1111-111111111111]
bases: [crm, billing]
communities: [6b1e0000-0000-4000-8000-000000000001]
它是一个路由保险丝,不是并发锁(不会协调并发编辑),也不是授权机制(授权才是安全边界)。它也不会选择目标——只会拒绝目标。
如何填充。 各轴独立初始化:当某个轴的集合为空时,首次成功拉取、推送或创建会将其填充。之后该集合只会按需扩展:自动绑定不会向非空集合追加内容。
如何执行。 wayai pull、wayai push、wayai publish 和 wayai relabel 会拒绝针对非空 hubs 集合之外的中心运行;wayai pull bases/<base> 和 wayai push bases/<base> 会拒绝针对非空 bases 集合之外的基础项运行;wayai pull communities/<x> 和 wayai push communities/<x> 会拒绝针对非空 communities 集合之外的社区运行。在某个轴已有范围限制的检出中创建新中心或基础项,也会以同样方式被拒绝。
如何更改。
wayai use <selector> # replace that axis with this one target
wayai use --add <selector> # widen: add one target to that axis
wayai unbind <selector> # drop one entry
wayai unbind # clear the whole scope, every axis
选择器的命名方式与 pull/push 相同:裸 UUID 表示中心,bases/<id> 和 --base <id> 表示基础项,hubs/<name> 和 --hub <x> 表示中心,communities/<folder|id> 和 --community <x> 表示社区;裸文件夹名称会在 hubs 和 bases 子树中查找(两处都存在时会被拒绝,不会猜测;绝不会作为社区处理)。wayai status 会显示当前范围;status --json 会通过 worktree_scope 字段携带该信息。
工作树合法地限定在多个实体范围内很正常——例如,一个基础项服务多个中心,或委派配置将中心 A 连接到中心 B。此类情况请用 --add 扩大范围;不要为了绕过限制而清除保险丝。
如果 push/pull 因范围限制而报错,请停止操作,并先询问用户。这通常意味着提示词原本是针对另一个工作树的。未经当前会话中的用户明确指示,不要运行 wayai unbind、wayai use(无论是否带 --add)、wayai bases unbind、wayai bases use,也不要编辑范围文件——扩大范围和清除范围限制一样,都是会话路由操作;两者都会改变用户认为你正在处理的中心、基础项或社区。
仓库结构
.wayai.yaml # DEPRECATED org binding — read as a fallback, never written.
# `wayai migrate` copies it into wayai-ws/wayai.yaml and
# KEEPS it (older CLIs still require it). Delete it only
# once every environment running this repo is current.
AGENTS.md / CLAUDE.md # STALE if present — an older CLI's root bootstrap; nothing
# writes or refreshes these now. Delete it, or (on a harness
# that auto-loads AGENTS.md) replace its body with a pointer
# to the skill — see "Retiring the old root AGENTS.md".
# Hub- and base-folder AGENTS.md are memory and are unaffected.
.claude/skills/wayai/ # Claude Code skill install (provisioned by `npx skills add wayai-pro/wayai-skill -y`)
├── SKILL.md
└── references/ # On-demand deep-dive references (see index below)
.opencode/skills/wayai/ # OpenCode skill install (same provisioner; same SKILL.md + references/ layout)
.agents/skills/wayai/ # Neutral skill install (same provisioner; same SKILL.md + references/ layout)
wayai-ws/ # All WayAI config-as-code (init creates wayai-ws/hubs/)
├── wayai.yaml # Workspace manifest — the repo's ONE committed config file
│ # `organization_id:` / `organization_name:` — which org this
│ # repo is scoped to. Written by `wayai init`; required.
│ # `default_hub:` / `default_base:` — OPTIONAL, which subtree a
│ # bare `wayai pull`/`push` targets. Declare AT MOST ONE:
│ # declaring both is a mixed invocation and is refused.
│ # Write these two by hand — no command creates them.
│ # `wayai init` keeps their VALUES when it rewrites the file,
│ # but YAML comments in it are not preserved.
├── org/ # Org-as-code — shared skills (wayai org pull/push)
│ ├── skills.yaml
│ └── skills/<skill_name>/
├── communities/ # One folder per community — `wayai pull communities/<community_id>`
│ └── <community-slug>/ # (see references/communities.md; push edits the LIVE community)
│ ├── community.yaml # Identity, settings, join link state, rooms, course folders in order — with ids and revs
│ ├── rules.md # The rules members see (Markdown); empty = none
│ └── courses/<course>/ # course.yaml (the course, its modules, each module's lessons in order)
│ └── lessons/<lesson>.md # and one file per lesson: its fields, then its text
├── bases/ # One folder per preview base (Data surface) — `wayai pull bases/<base>`
│ └── <base-id>/
│ ├── base.yaml # Base identity; `wayai use bases/<folder>` reads it
│ ├── record-types/<id>.yaml # One file per entity, per kind. Secrets are never written
│ ├── relationship-types/<id>.yaml
│ ├── file-types/<id>.yaml
│ ├── inbound-webhooks/<id>.yaml
│ ├── triggers/<id>.yaml
│ ├── toolsets/<id>.yaml
│ ├── actions/<id>.yaml
│ └── seeds/<id>.yaml
└── hubs/
└── <hub-slug>--<label>/ # One folder per preview hub (disambiguated)
├── hub.yaml # Hub config + states + connections + automations + skills
├── agents/
│ ├── <slug>.yaml # Agent config (one per agent, slugified name)
│ └── <slug>.md # Agent instructions (one per agent)
├── evals/ # Eval scenarios (synced)
│ ├── <name>.yaml
│ └── <set>/<name>.yaml
├── journeys/ # Eval journeys (synced; flat folder, one file per journey)
│ └── <slug>.yaml
├── attachments/ # Eval/journey turn attachment files (synced; hub-root, shared by evals + journeys)
├── call-openings/ # Voice agents' own call opening audio (synced; `call_openings` in agents/<slug>.yaml)
├── skills/<skill_name>/ # Skill files (synced)
├── AGENTS.md # Hub-specific memory — scaffold seeded on pull/push (NOT synced; fill it in)
└── references/ # Hub-specific supporting files (NOT synced)
└── <hub-slug>/ # Linked production hub: READ-ONLY mirror (bare slug, no --label). Refreshed each pull; never pushed
预览中心文件夹使用 hub-slug--<preview_label> 或 hub-slug--<hub_id_prefix> 以便区分;关联的生产中心会映射到不带后缀的 hub-slug。仍使用旧版 workspace/ + 根目录 org/ 布局的现有仓库仍可正常工作(CLI 两种布局都能读取)——运行 wayai migrate 可迁移到 wayai-ws/。
hub.yaml 结构
version: 1
hub_id: "abc-123-def" # set by `wayai pull` — do not edit
hub_environment: preview # set by `wayai pull` — do not edit
preview_label: experiment-a # server-owned, set by `wayai pull` — do not edit (only on previews; sets the hub folder's `--<label>` suffix). Editing here is IGNORED on push (push warns); change it with `wayai relabel <label>` / `--clear`, or set it at creation with `wayai create --label` / `wayai replicate --label` / `wayai push --label`
hub:
name: Customer Support
# description: Handles refunds, order status, and billing questions # optional, human-facing
hub_type: chat # chat | task
ai_mode: pilot+copilot # pilot | copilot | pilot+copilot | turned_off
timezone: America/New_York
non_app_permission: everyone
# tags: [retail, vip] # org tag slug names (create in UI first); gate which org credentials this hub can resolve. Omit to leave unchanged; [] clears; only an org admin may change them. See references/connections.md#organization-tags
# auto_close_inactive_days: 7 # force-close a conversation after N days of inactivity (see Hub Settings)
# conversation_retention_days: 7 # keep an ended conversation's DO alive N days for post-hoc `annotate` (see Hub Settings)
# display_names: { en: Customer Support, pt: Atendimento ao Cliente, es: Atención al Cliente } # end-user name per app language (see Hub Settings)
# welcome_messages: { en: "Hi! How can I help?", pt: "Olá! Como posso ajudar?", es: "¡Hola! ¿Cómo puedo ayudar?" }
# starter_questions: { en: ["Where is my order?"], pt: ["Onde está meu pedido?"], es: ["¿Dónde está mi pedido?"] } # up to 4 per language
# end_user_daily_message_limit: 50 # messages one end user may send in the app per 24 hours; null removes it (see Hub Settings)
kanban_statuses: # full field specs + constraints: references/kanban.md
- slug: new
name: New
order: 0
color: "#22c55e"
isInitialStatus: true
allowed_next_statuses: [in_progress, waiting_for_customer, resolved]
- slug: in_progress
name: In Progress
order: 1
color: "#3b82f6"
triggersAgentResponse: true # transition fires an agent turn; can carry additional_context_schema + additional_instructions (see references/kanban.md)
allowed_next_statuses: [waiting_for_customer, resolved]
- slug: waiting_for_customer
name: Waiting for Customer
order: 2
color: "#f59e0b"
allowed_next_statuses: [resolved]
followups:
- order: 0
type: inactivity
threshold: 30
timeUnit: minutes
instructions: "Hi! Just checking in — do you still need help?"
- slug: resolved
name: Resolved
order: 3
color: "#ef4444"
isTerminalStatus: true # at most one terminal status per hub
outcomes: # terminal-transition policy; selected slug → data.meta.outcome
- { slug: resolved, name: Resolved, color: "#22c55e", from_statuses: [in_progress, waiting_for_customer] }
- { slug: canceled, name: Canceled, color: "#ef4444" }
- { slug: abandoned, name: Abandoned, color: "#a0aec0" }
states:
- id: "state-uuid-789" # set by pull
slug: order_tracking # immutable identifier; auto-derived from name if omitted
name: order_tracking
scope: conversation # conversation | user
description: Tracks current order
json_schema:
type: object
properties:
order_id: { type: string }
status: { type: string, enum: [pending, shipped, delivered] }
initial_value: { status: pending } # must validate against json_schema
connections:
- name: anthropic
type: Agent
service: Anthropic
# sync_credentials_to_production: true # default; false keeps production's credential separate (set it via `wayai set-connection-credential`). See references/connections.md#credential-propagation-to-production-sync_credentials_to_production
- name: my-api-connection
type: Tool
service: REST API
base_url: https://api.example.com # Its credential is only sent to this origin: required for custom tools while it holds one
- name: elevenlabs-tts
type: TTS
service: ElevenLabs TTS
settings: # Per-connection params (voice/model/language, etc.); keys = connector_settings_schema. See references/connections.md
voiceId: pNInz6obpgDQGcFmaJgB
modelId: eleven_multilingual_v2
hub.yaml 还包含 skills:、automations: 和 contact_lists: 块。完整架构请参阅各领域的参考文档。
agents/<slug>.yaml 结构
id: "agent-uuid-123" # set by pull
name: Pilot Agent
role: pilot
connection: anthropic # connection display name
# instructions resolved by convention from agents/<slug>.md
# additional_context_template: # per-turn context, emitted as an <additional_context> tag on the last user message (same {{...}} syntax as instructions). Put high-churn placeholders ({{now()}}, {{state()}}) HERE, not in instructions, to keep the system prompt cache-stable (see references/agents/instructions.md#additional-context-cache-friendly)
# response_format: # {schema_name, schema_json} — force structured JSON output instead of free text (see references/agents/roles-and-settings.md#response-format-structured-output)
# enabled: true # default; omitted
# include_message_timestamps: false # default; when true, appends [timestamp, weekday, daypart] to user messages
# previous_conversations_count: 3 # off by default (max 20); this user's N most recent ended conversations, prepended to the FIRST user message and frozen at the first agent turn that uses it. Foreground roles only; `0` clears it (omitting the key on update leaves it as-is); summaries come from the conversation_evaluator (see references/agents/roles-and-settings.md#previous-conversations-context)
settings:
model: claude-sonnet-5-5
max_tokens: 4096
# temperature (only sampling knob): Sonnet 5+ / Haiku 5.5 / Opus 4.7+ / Fable strip a non-default value — set it only on Opus 4.6 / Sonnet 4.6 & older
# reasoning per provider: Anthropic thinking_enabled + effort · OpenAI/OpenRouter/xAI reasoning_effort · Gemini reasoning_level (see roles-and-settings.md)
# file_handling_mode: no longer changes what the model receives (earlier files are always announced by path, never re-attached); metadata_only still auto-enables read_file. max_attachment_size_mb is inert (see roles-and-settings.md#file-handling-all-llm-connectors)
# deliver_preamble: true # default; pre-tool "let me check…" text is delivered as its own message (voice: own TTS clip; ignored on email). false = only the final reply (see roles-and-settings.md#pre-tool-preamble-delivery-all-llm-connectors)
# copilot_trigger: every_message # copilot-track only; on_demand suppresses the automatic per-message suggestion — the team pulls one via the "Suggest reply" button (cost/noise lever; see roles-and-settings.md)
tools:
native:
- update_kanban_status
- get_state
- update_state
delegation:
- type: agent
tool: transfer_to_agent
target: Specialist - Billing
- type: team
tool: transfer_to_team
target: Tier 2 Support
# Hub-as-agent: hand a self-contained request to ANOTHER hub in this org.
# `target` is a PRODUCTION (published) hub name. context_boundary is required
# reading — see "Hub delegation" below.
- type: hub
tool: delegate_to_hub
target: Billing Hub
context_boundary: summary # instruction | summary | transcript
custom:
- name: check_order_status
description: Check order status by email
method: post
path: /api/orders/status
body_format: json
connection: my-api-connection
config:
name: check_order_status
description: Check order status by email
parameters:
type: object
properties:
email: { type: string, description: Customer email }
required: [email]
skills:
- name: Order Management # links a hub skill by name (see Skills)
skill_id: "skill-uuid" # set by pull
priority: 0
完整的 Agent 选项(每个连接器的设置、additional_context_template、response_format、文件处理、本机工具参数、自定义工具字段、composed_tools、占位符)请参阅 references/agents/。
评估变量——conversation_evaluator / message_evaluator Agent 会携带 evaluation_variables 列表(它们为每个对话/消息输出的结构化字段,这些字段会成为 Analytics 中的 data.variables.*),并通过 pull/push 保持往返一致。请参阅 references/agents/roles-and-settings.md。monitor 会在同一列表中声明其 flag_conditions 和 rules 所读取的字段;这些字段仅用于其条件,不会进入 Analytics(监控配置)。
关键规则
- 只读字段:
hub_id、hub_environment、id——由wayai pull设置,切勿编辑 - 自动创建连接:
hub.yaml中的非 OAuth 连接会通过匹配service+authentication_type解析为组织凭据。如果多个组织凭据具有相同的认证类型,可使用credential字段消除歧义。OAuth 连接(WhatsApp、Instagram、MCP OAuth)必须预先创建(通过 UI 设置——参见 OAuth 连接交接)——只按名称引用 - 生产凭据: 默认情况下,发布/同步时连接会将其凭据复制到生产环境。设置
sync_credentials_to_production: false可让生产环境使用独立凭据,然后通过wayai set-connection-credential直接设置(其他情况下生产环境为只读)。无论标志如何设置,基础工具集连接的令牌都不会被复制:始终设置生产环境自己的令牌。托管 Agent 连接的 webhook 签名密钥(Claude Agent (Managed))也不会被复制:每个 hub 都会注册自己的端点并设置自己的密钥。参见references/connections.md - 组织标签:
hub.tags(slug 名称,须先在 UI 中创建)决定 hub 可解析哪些组织凭据(匹配规则见上文「连接和凭据」)。只有组织管理员可以更改这些标签;任何人都可以推送不更改标签的内容。标签的 slug 是永久的——UI 只会编辑其显示名称和颜色——因此这些列表无需重写。参见references/connections.md - 工具组:
native(按名称指定的平台内置工具)、delegation(Agent 间/团队移交)、custom(带连接的 HTTP 端点)、mcp(来自 MCP Server 连接的工具,按name+connection指定——推送时会发现并分配;参见 references/agents/native-tools.md)。关于如何设计要公开的参数/工具:references/agents/tool-principles.md - 名称是外键: 跨实体引用在推送/运行时通过显示名称解析——Agent 的
connection:、委派的target:(Agent 名称或由 UI 管理的团队名称)、Agent 的skills[].name、评估的agent:、自定义工具的connection:。悬空名称会导致推送失败或运行时调用失败——重命名任何内容时,都要在同一次编辑中更新引用它的实体 - 重命名: 更改
name字段——稳定的id可确保系统将其识别为重命名,而非删除后新建。对于 Agent,wayai push会自动重命名.yaml和.md文件 - 省略默认值: 与默认值一致的字段会被省略(例如,
enabled: true、看板标志默认为false、excludeHolidays默认为true) - 实体匹配(同步/差异): 优先使用
id(稳定的 UUID),之后再回退到其他方式。例外情况:状态按name匹配(无论作用域如何,在每个 hub 内唯一);评估按name + path匹配;原生工具按每个 Agent 的tool_name匹配
Slug 化与实体匹配
名称 → 用于文件名的 URL 安全 slug:
- 转为小写
- 标准化重音字符(NFD + 移除变音符号)
- 将非字母数字字符替换为
- - 合并连续的
- - 去除开头和结尾的
- - 限制为 50 个字符
示例:Mario's Pizza → marios-pizza;Suporte Nível 2 → suporte-nivel-2;Specialist - Billing → specialist-billing。
编辑 Agent 指令
- 文件:与对应的
.yaml文件位于同一目录下的agents/<slugified-agent-name>.md - 始终将文件保存到
wayai-ws/hubs/<hub>/agents/,绝不要保存到/tmp或其他路径 - 编辑前始终先运行
wayai pull,以免覆盖外部修改 - 指令支持动态占位符:
{{now()}}、{{user_name()}}、{{state()}}等——请参阅references/agents/instructions.md - 可靠性结构:每个
.md文件都按步骤 → 护栏 → 语气的顺序组织;说明要做什么(而非要避免什么);将每个操作写成一个具名工具调用。组织提示词,让模型最先、最容易执行正确的操作。完整原则请参阅:references/agents/prompt-principles.md
参考文档
每个领域对应一份参考文档,并遵循 hub 导航顺序。本文介绍相关概念;准备编写该领域的 YAML、需要了解字段级架构或特定提供商的详情,或正在排查该领域的行为时,请打开相应领域的参考文档。
| 领域 | 参考文档 | 阅读时机 |
|---|---|---|
| 连接 | references/connections.md | 配置渠道、Agent 提供方、工具 API 或语音连接器;绑定凭据、组织标签、生产凭据 |
| Agents | references/agents/roles-and-settings.md | 选择 Agent 角色、委派流程、连接器专属设置、评估变量、响应格式 |
| Agents | references/agents/native-tools.md | 原生工具目录及参数、元工具(get_tool_schema、execute_tool)、MCP 工具分配 |
| Agents | references/agents/custom-tools.md | 自定义 HTTP 工具格式、OpenAI 函数架构、composed_tools 的副作用 |
| Agents | references/agents/tool-principles.md | 设计可靠易用的工具界面,供容易出错的 Agent 调用——工具界面整理 > 验证 > 提示词、一个工具对应一个意图、错误明确暴露、受保护的原子操作 |
| Agents | references/agents/instructions.md | agents/<slug>.md 的占位符语法({{now()}}、{{state()}} 等) |
| Agents | references/agents/prompt-principles.md | 放置和组织上下文以确保可靠执行——上下文与插槽生命周期、缓存卫生、状态与工具历史、流程优先于风格、积极表达、将语气单独设为一节 |
| 看板 | references/kanban.md | 看板字段规范:标志、状态转换、后续操作、附加上下文架构/说明、泳道、约束矩阵、警告 |
| 状态 | references/states.md | 状态 JSON 架构、范围、Agent 读写、初始值 |
| 技能 | references/skills.md | 技能(skills:、skills/<skill_name>/)、Agent 关联、将拉取的文件夹转换为技能前的操作、提供方同步(wayai sync-skills) |
| 语音通话 | references/calls.md | 为实时 AI 语音通话设置 hub:Realtime 连接、pilot_voice Agent、网页通话及其开场白(AI 通知、WayAI 的开场白或你自己的开场白)、AI 可以接听的对象、转接、口头确认、结束通话、团队看到的内容、录音、计费、限制 |
| 评估 | references/evals.md | 评估场景 YAML、场景集、代码化旅程、种子数据和变量、wayai eval capture / wayai eval journey capture、运行节奏、通话评估(run-eval --call-mode、wayai eval call)、编写和解读原则 |
| 自动化 | references/automations.md | 自动化(计划、事件或 webhook 触发器、联系人列表或无目标、send_message / run_agent)、webhook 投递(签名、密钥、轮换)、各 hub 类型的有效组合、任务 hub 任务、门控、缺少键与 [] 的区别、启用、暂停和立即运行、消息模板、限制、hub 列表(contact_lists:)、组织的联系人簿(联系人、可见性、组织列表、CSV 导入) |
| 社区 | references/communities.md | wayai communities:列出组织的社区、读取、轮换或关闭加入链接、来源标签、统计信息、仅限邀请的社区访问列表;允许运行该命令的人员(所有者和管理员,仅限浏览器登录)及其错误。将社区作为代码管理:community.yaml(其 admission)、rules.md 和课程(course.yaml、课程文件)、房间密钥、名称和修订版本、列表顺序、pull 和 push 的判定方式、冲突、限制、--dry-run / --theirs |
| 分析 | references/analytics.md | 变量类别/类型、筛选运算符、时间分析、查询工作流 |
| Bases | references/bases/README.md | 开展任何 base 工作前请先阅读——Data 对象模型、预览/发布规则,以及指向下方文件的路由图 |
| Bases | references/bases/records.md | 记录类型架构、记录、筛选器 DSL 和 search、日期时间、部分更新、取消/归档、x-fk、已审核记录(x-review)及 Agent 备注方案、关系类型、关系、批处理、批量导入 |
| Bases | references/bases/querying.md | wayai bases sql——表、必需的范围限定谓词、JSON 子列、示例集;x-search 调优和时区配置 |
| Bases | references/bases/files.md | 文件类型、按路径寻址的版本化文件、历史记录/差异、S3 挂载、记录附件 |
| Bases | references/bases/config-as-code.md | wayai-ws/bases/<base>/、子树路由和拒绝混合调用、base.yaml、发布/回滚、评估模式、种子数据和租约 |
| Bases | references/bases/integrations.md | 以规范模型优先的建模方式和模式目录;外部来源、入站 webhook、触发器、提供方适配器 |
| Bases | references/bases/toolsets.md | 操作和工具集(面向 Agent 的 MCP 界面)、filterable_fields/writable_fields/base_filter/precondition、base API 令牌、base 凭据、建模和工具设计原则 |
| Bases | references/bases/executors.md | 构建代表触发器或外部来源与外部世界交互的 HTTP 服务 |
| 规范示例 | references/canonical-example/README.md | 端到端 hub,展示 hub.yaml + agents/* + evals/ + journeys/ 如何交叉引用,以及其 Agent 如何从知识库读取组织的文档。完全从头生成新 hub 前,请先阅读一次 |
| 仓库 Agent 模板 | references/repository-agent/README.md | 在单个 GitHub 仓库中工作的托管 Agent:先读取仓库的 AGENTS.md,从分支或提交开始(repo_checkout),只推送自己的分支。可复制到 hub 的 agents/ 中的文件 |
| 使用应用 | references/using-the-app.md | 如何为终端用户(Hub User)提供帮助:Agent 列表、聊天和任务 Agent、撰写和附加内容、文件、人员何时接听、账户、通知、移动应用和桌面应用 |
| 支持收件箱 | references/support-inbox.md | 如何为支持团队成员或 hub 管理员提供帮助:收件箱及其标签页、看板、认领/接管、转接、关闭、回复和 24 小时窗口、Copilot 建议、咨询、联系人审批、通知、移动应用中的支持功能 |
| 导航 | references/navigation.md | 应用 URL 界面(/chat、/support、/settings/...)、hub 详情页标签、查询字符串深层链接——任何需要向用户提供 URL 的时候;链接在移动应用中的打开方式,以及桌面应用(获取方式、与浏览器版相比新增的功能、设置) |
| AGENTS.md 文件 | references/agents-md-template.md | 每个 hub / base 文件夹的记忆模式——AGENTS.md 应包含哪些内容,以及 CLI 会为哪一个生成初始文件 |