
Byted Livesaas Master
- 8 installs
- 411 repo stars
- Updated August 4, 2026
- bytedance/agentkit-samples
byted-livesaas-master is a Claude skill that operates Volcengine enterprise livestreaming (rooms, comments, audience control, live analytics) through the bytedlive CLI.
About
This skill lets an agent operate Volcengine enterprise livestreaming through the bytedlive CLI. A developer uses it to manage live-room lifecycle, post and moderate comments, push system messages, control audiences (mute, block, kick), run product-card and marketing operations, and query live data and audience profiles, with an OpenAPI fallback. It requires AK/SK credentials configured locally and gates all write operations behind plain-language confirmations.
- Drives Volcengine enterprise LiveSaaS via the bytedlive CLI for room lifecycle, comments and audience control
- Covers live data and audience-profile analytics, product-card operations, and marketing card tools
- Enforces human-in-the-loop confirmations and a blacklist double-confirm for high-risk operations
Byted Livesaas Master by the numbers
- 8 all-time installs (skills.sh)
- Ranked #1,519 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
byted-livesaas-master capabilities & compatibility
Requires Volcengine LiveSaaS AK/SK credentials; billed by Volcengine, not free.
- Capabilities
- livestream control · comment moderation · audience management
- Use cases
- orchestration · data analysis
- Pricing
- Bring your own API key
What byted-livesaas-master says it does
所有命令必须通过 `bytedlive` CLI,禁止手写 curl 或未文档化的 HTTP 请求。
**Base URL** | 固定 `https://livesaas.volcengineapi.com/`
未安装时先引导安装:`npm i -g bytedlive-cli`
npx skills add https://github.com/bytedance/agentkit-samples --skill byted-livesaas-masterAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 8 |
|---|---|
| repo stars | ★ 411 |
| Last updated | August 4, 2026 |
| Repository | bytedance/agentkit-samples ↗ |
What it does
Operate Volcengine enterprise livestream rooms, comments, audiences and analytics through the bytedlive CLI.
Who is it for?
Managing enterprise live-room lifecycle, moderating comments, controlling audiences, and querying live data and audience profiles.
Skip if: Low-level streaming/encoding issues, WebSDK integration, or billing and plan management, which are out of scope.
When should I use this skill?
The user wants to create or control an enterprise live room, moderate comments, mute or kick audience members, or query live data.
What you get
Executes live-room control, moderation and analytics through the bytedlive CLI with confirmation gates on every write.
- live-room control actions
- comment and audience moderation
- live data and audience-profile queries
By the numbers
- 8 capability areas in the ability overview table
- 3-tier architecture: Skill, Agent, CLI
Files
byted-livesaas-master(企业直播控播)
0. 启动埋点
每次启用本 Skill 时,先 best-effort 执行一次埋点脚本,再继续处理用户请求;脚本失败、超时或接口不可达时不得中断任务。
node tools/report_usage.js脚本根据 Skill 安装路径自动识别 Agent(如 ~/.cursor/skills/ → cursor,~/.codex/skills/ → codex)。禁止在未识别当前环境时硬编码 --agent codex。仅在自定义安装目录(skills add --target)或自动识别失败时,显式传入 --agent cursor|codex|claude-code|trae|openclaw;仍无法识别时使用 unknown。该脚本由 Node/CLI 发起 POST 上报,不支持浏览器页面跨域调用。
1. 适用范围
When to use
当用户意图涉及以下任一场景时触发本 Skill:
- 直播间生命周期管理与管控:创建/删除直播间,查询列表,修改基础配置(名称/时间/模式),控制状态(开播/锁定/恢复/下播/封禁)
- 直播数据分析与观众画像:查询直播间观看时长分布统计、拉取观众用户画像明细用于洞察
- 商品库与卡片运营:直播中对商品卡片进行上架、讲解态切换,查询商品状态或统计数据
- 评论治理与内容分析:发送/查询/轮询评论,删除用户消息,配置敏感词,或获取评论的分析结果(含大模型分析)
- 账号基础信息与媒资库运维:获取账号配置/全局权益额度信息,批量删除媒资库视频,检查文档库容量
- 营销互动与连麦控制:创建直播间卡券等互动工具,管理网页直播连麦协同状态
- 系统消息:向直播间推送系统定制消息
- 观众管控:针对观众的禁言、拉黑、踢出
- 观看页外观:切换主题(暗黑/清爽/经典/传统节庆)
- OpenAPI 兜底:上述未明确覆盖到的其余企业直播能力操控需求,通过调用企业直播OpenAPI来实现
When NOT to use
- 推流/拉流/编码等底层媒体问题 → 不属于本 Skill
- WebSDK 接入 / 小程序进房 / 观看端 Token → 使用 byted-livesaas-dev Skill
- 账号计费 / 套餐管理 → 引导用户至火山引擎控制台
- 非企业直播产品(如视频点播、RTC)→ 不属于本 Skill
2. 架构概览
用户意图 → Skill(路由 + 约束) → Agent 生成 CLI 命令 → bytedlive CLI 执行- Skill 层:定义意图到 CLI 子命令的映射 + 执行约束(不含可执行脚本)
- Agent 层:根据路由表与约束拼装
bytedlive命令并执行 - CLI 层:封装凭证管理、签名、请求发送、确认交互与 JSON 结果
唯一执行入口:所有命令必须通过 bytedlive CLI,禁止手写 curl 或未文档化的 HTTP 请求。3. 首次使用引导与依赖安装(Onboarding)
触发条件:本 Skill 被首次激活时(即用户第一次发出匹配 §1 触发词的请求),Agent 必须先执行 onboarding 流程(含 CLI 自动安装与凭证配置),再处理用户的实际请求。
3.1 Onboarding 检查与安装流程
Step 0: 环境检查与 CLI 自动安装
├─ 检查依赖:执行 `bytedlive --version` 判断是否已安装
├─ 未安装时先引导安装:`npm i -g bytedlive-cli`
├─ Agent 有权限时可静默执行安装
├─ 成功:执行 `bytedlive --version` 验证后进入 Step 1
└─ 失败:输出【CLI 安装失败引导】(见 3.2),中止后续流程,等待用户手动处理
Step 1: 检查凭证 → bytedlive openapi check-credentials --pretty
├─ 成功(已配置) → 跳过引导,直接处理用户请求
└─ 失败(未配置 / 凭证无效) → 进入 Step 2
Step 2: 输出【AK/SK 本地配置引导消息】(见 3.3)
Step 3: 用户在本地终端执行 set-credentials,CLI 写入凭证并验证
Step 4: 验证通过 → 继续处理用户的原始请求3.2 CLI 安装失败引导模板
当 Step 0 的自动安装失败(如缺少 Node 环境、无权限等)时,Agent 必须向用户输出以下消息:
⚠️ 环境依赖缺失
>
抱歉,我尝试为你自动安装底层依赖工具 bytedlive-cli 但失败了(通常是因为当前环境未安装 Node.js / npm 或缺少全局写入权限)。>
请在你的本地终端中执行以下命令手动安装:
```bash
npm i -g bytedlive-cli
```
安装完成后执行 bytedlive --version 验证,并回复我“已安装”,我将带你继续下一步配置。3.3 AK/SK 本地配置引导模板
当检测到凭证未配置时,Agent 必须输出以下消息(可根据上下文微调措辞,但核心信息不可缺少):
---
👋 欢迎使用企业直播控播 Skill!
>
检测到你还没有绑定企业直播账号,需要先完成一次配置。
>
请在你的本地终端执行下面的命令,按提示隐藏输入 Access Key(AK) 和 Secret Key(SK):
>
```bash
bytedlive openapi set-credentials
```
>
- 获取路径:火山引擎控制台 → 密钥管理
>
⚠️ 不要把 AK/SK 发到对话里。CLI 会把密钥缓存在本地 ~/.bytedlive/openapi-credentials.json,后续命令会自动读取。>
配置成功后回复我“已配置”,我会继续处理刚才的请求。
---
3.4 凭证写入与验证
用户在本地终端执行:
bytedlive openapi set-credentials| 验证结果 | Agent 行为 |
|---|---|
成功(set-credentials 返回 ok) | 输出 ✅ 账号绑定成功!,然后继续处理用户的原始请求 |
| 失败(401/403/签名错误) | 输出 ❌ 凭证验证失败,请检查 AK/SK 是否正确。,引导用户在本地终端重新执行 bytedlive openapi set-credentials |
| 失败(网络错误) | 输出 ⚠️ 网络连接异常,请稍后重试。 |
3.5 Onboarding 状态记忆
- 凭证验证通过后,本会话内不再重复 onboarding
- 凭证已持久化到
~/.bytedlive/openapi-credentials.json,后续会话自动加载,无需重复配置 - 如果后续操作中出现凭证失效(401/403),按 §7 错误恢复策略处理,不重新走完整 onboarding
3.6 快速能力概览(验证通过后附带)
凭证验证通过后,在确认消息中追加一段能力概览,帮助用户快速了解可以做什么:
✅ 账号绑定成功! 以下是我可以帮你做的事情:
>
| 能力 | 示例指令 |
|------|---------|
| 🎬 直播间管理 | "创建一个明天下午3点的直播间" / "查看最近的直播间" |
| 💬 评论互动 | "帮我在直播间发一条评论" / "查看最近的弹幕" |
| 📢 系统消息 | "发一条系统公告" |
| 🚫 观众管控 | "禁言某个用户" / "把捣乱的人踢出去" |
| 📊 数据与画像 | "查询直播间观看时长" / "获取观众画像详情" |
| 🛒 商品与卡片 | "给商品卡片上架" / "切换到讲解状态" |
| 🎨 观看页外观 | "切换到暗黑模式" |
| 🔧 OpenAPI | "调用 GetActivityAPI 查直播间详情" |
>
现在帮你处理刚才的请求 👇
4. 凭证与 Base URL
| 项目 | 规则 |
|---|---|
| AK/SK | 必需。执行任何 OpenAPI 操作前,必须先执行 bytedlive openapi check-credentials --pretty。若本地缓存可用,直接复用;若不可用,只引导用户在本地终端运行 bytedlive openapi set-credentials,禁止在对话中索要 AK/SK |
| Base URL | 固定 https://livesaas.volcengineapi.com/,不向用户询问。仅用户主动提供专用 endpoint 时通过 BYTEDLIVE_BASE_URL 覆盖 |
| 缓存优先级 | 命令行/环境变量 → 会话缓存 → 本地文件 ~/.bytedlive/openapi-credentials.json |
| 凭证失效 | 401/403/签名错误时,引导用户本地执行 bytedlive openapi clear-credentials 后再执行 bytedlive openapi set-credentials |
5. 安全机制:确认与黑名单
5.1 拟人化业务确认(所有写操作必做)
1. 组装候选命令(仅在后台准备,绝对不向用户展示具体的 CLI 命令、代码或 JSON 参数)。 2. 用“大白话”向用户确认业务意图,例如:“我准备为您创建名为『测试签到』的直播间,时间是今天下午 3 点。确认要建吗?” 3. 仅当用户明确同意后才执行。
5.2 黑名单二次确认(高风险操作)
命中以下操作时,在常规确认通过后,再追加一次确认:
| 黑名单操作 | 示例命令 |
|---|---|
所有删除类(含 delete/remove/del/删除) | bytedlive control room ...(删除相关) |
| 观众踢出 | bytedlive control audience kick ... |
| 观众封禁/拉黑 | bytedlive control audience block ... |
二次确认话术需同样拟人化:您正在进行高风险操作(例如:踢出某个观众),这可能会影响观众体验或导致数据丢失。请最后确认一次是否继续?
6. 参数获取引导(缺参时 Agent 怎么办)
| 缺失参数 | Agent 应做的事 |
|---|---|
--activity-id | 先执行 bytedlive control room list 查询最近直播间,让用户确认目标 |
--user-ids(观众管控) | 询问用户提供目标用户标识,或引导查询评论列表获取 |
| 直播间图片素材(封面/角标/装饰图等) | 不支持直接上传图片配置直播间。优先让客户提供可访问的图片 URL 并继续后续配置流程;若客户无法提供 URL,则引导客户直接使用火山引擎控制台完成上传与配置(无回调流程) |
| AK/SK | 先执行 bytedlive openapi check-credentials --pretty;无缓存或验证失败时,引导用户本地执行 bytedlive openapi set-credentials,不要在对话中索要 |
| 不确定的 flag | 执行 bytedlive control <子命令> --help 查看帮助 |
7. 错误恢复策略
7.1 回答与执行约束(强制)
- 证据优先级:必须优先基于本 Skill 已定义流程、已有 CLI 能力(
bytedlive control/openapi)与本地知识库/参考文档作答和执行,不得跳过现有能力直接猜测。 - 官网补证:当现有知识库、CLI 帮助与本地规则无法解决问题或无法确认参数/行为时,必须到 火山引擎文档中心 检索对应企业直播文档并据此补证后再回复。
- 无法实现/无法确认兜底:若已穷尽本地能力与官网检索仍无法落地,必须明确告知用户「当前暂无法实现该能力」或「当前暂无法准确回答该问题」,并说明卡点;禁止编造接口、版本、字段、结果或“肯定可行”的承诺。
| 错误类型 | Agent 处理方式 |
|---|---|
missing openapi credentials | 引导用户本地执行 bytedlive openapi set-credentials |
| 401 / 403 / 签名错误 | 凭证可能过期或错误,提示用户本地执行 bytedlive openapi clear-credentials 后再执行 bytedlive openapi set-credentials |
InvalidActionOrVersion / Action 不存在 | 按 §11 流程进行大模型静默自愈。失败则动用联网搜索查真实版本号并重试。期间安抚用户,切勿抛出生涩的原始报错信息。 |
| 参数错误 / 缺必传字段 | 检查字段名是否与官方文档一致(参考 §10 字段名规范),补全后重试 |
| 网络超时 | 重试 1 次,仍失败则告知用户 |
| 未知错误 | 查 火山引擎企业直播文档,无法解决则建议工单 |
8. 全局选项
| 选项 | 作用 |
|---|---|
--pretty | JSON 美化输出 |
--non-interactive | 禁止交互;缺参或缺凭证则直接失败 |
-y / --yes | 跳过操作前确认(凭证仍需可用) |
9. 命令路由表
9.1 直播间(bytedlive control room)
| 场景 | 命令 | API | 关键参数 |
|---|---|---|---|
| 创建直播间 | bytedlive control room create | CreateActivityAPIV2 | --name、--start/--live-time、--end/--end-time |
| 直播间列表 | bytedlive control room list | ListActivityAPI | --page/--page-size、--name、--status、--sort-by/--sort-order(支持 desc/asc 或 Desc/Asc) |
| 读基础配置 | bytedlive control room config get --activity-id <id> | GetActivityBasicConfigAPI | |
| 更新基础配置 | bytedlive control room config update --activity-id <id> | UpdateActivityBasicConfigAPI | --name、--start、--end、--view-url-path、--activity-type、--live-mode |
| 设置活动状态 | bytedlive control room status set --activity-id <id> | UpdateActivityStatusAPI | --op(3/4/5)或 `--action recover\ |
创建直播间成功回复模板(强制)
当创建直播间成功后,Agent 的回复中必须包含以下三类地址(由 ActivityId 动态拼接),便于用户直接进入控制台操作与网页开播:
- 控制台地址:
https://console.volcengine.com/livesaas/liveManagement/<ActivityId> - 网页开播地址:
https://console.volcengine.com/livesaas/webpush/micromode/<ActivityId> - 观看页地址:接口返回的
ViewUrl(若有)
推荐回复模板:
直播间已创建成功。
- 直播间名称:<Name>
- ActivityId:<ActivityId>
- 状态:<StatusDesc>
- 控制台地址:https://console.volcengine.com/livesaas/liveManagement/<ActivityId>
- 网页开播地址:https://console.volcengine.com/livesaas/webpush/micromode/<ActivityId>
- 观看页地址:<ViewUrl>9.2 评论(bytedlive control comment)
| 场景 | 命令 | API | 关键参数 |
|---|---|---|---|
| 发送评论 | bytedlive control comment send --activity-id <id> --comment <文本> | PresenterChatAPIV2 | 可选 --audience-group-id、--top-status |
| 评论列表 | bytedlive control comment list --activity-id <id> | ListActivityChatAPI | 可选分页、时间、--chat-type、--top-status |
| 轮询评论 | bytedlive control comment poll --activity-id <id> | PollingChatAPI | 可选 --last-chat-id、--page-size、--start-time/--end-time |
9.3 系统消息(bytedlive control system-message)
| 场景 | 命令 | API | 关键参数 |
|---|---|---|---|
| 发送系统消息 | bytedlive control system-message send --activity-id <id> --content <文本> | SendCustomSystemMessageAPI | 可选 --message-type |
9.4 观众管控(bytedlive control audience)
均需 --activity-id。用户标识常用 --user-ids,部分场景可用 --cookies 或 --external-user-ids(以 --help 为准)。
| 场景 | 命令 |
|---|---|
| 禁言 | bytedlive control audience mute --activity-id <id> --user-ids <...> |
| 拉黑(⚠️ 黑名单) | bytedlive control audience block --activity-id <id> --user-ids <...> |
| 踢人(⚠️ 黑名单) | bytedlive control audience kick --activity-id <id> --user-ids <...> |
9.5 观看页外观(主题切换)
当用户意图是「切换主题/换皮肤/外观设置」时,需做意图识别后再执行:
| 主题 | 同义词 |
|---|---|
| 暗黑模式 | 暗黑、深色、夜间、黑色主题、dark |
| 清爽模式 | 清爽、浅色、简洁、明亮、light |
| 经典模式 | 经典、默认、原版、标准 |
| 传统节庆 | 节庆、喜庆、春节、新年红、红色主题 |
规则:
- 命中唯一主题 → 正常确认后执行
- 命中多个或未命中 → 反问:
你想切换到哪一种主题?可选:暗黑模式 / 清爽模式 / 经典模式 / 传统节庆。 - 用户仅说「换个主题」等模糊描述 → 视为未命中,走反问
9.6 高频 OpenAPI 调用场景(使用兜底)
对于尚未被 CLI 工具(control 子命令)封装的高频业务场景,Agent 应当直接通过 openapi call 进行调用。常见高频场景和对应的 Action 如下(请勿编造 CLI 命令):
| 场景分类 | 代表性 Action (API) | 用途说明 |
|---|---|---|
| 直播数据与画像 | AnalysisUserBehaviorPeopleV2 / GetAccountUserTrackData | 获取观看时长分布与观众画像详情 |
| 商品运营 | EnableProduct / ExplainProduct | 商品卡片上架与切换至讲解状态 |
| 账号与全局信息 | GetAccount / GetAccountConfig | 查询账号初始化信息与全局配置 |
| 媒资与文档库 | DeleteMediaLibraryVideoAPI / CheckDocLibStorageCapacity | 批量删除回放视频与查询文档容量 |
| 评论治理与分析 | DeleteUserMessage / GetAccountCommentAnalysisLLMConsole | 删除单条评论或获取大模型评论分析 |
| 线路与推拉流 | ActivityLines / ActivityLinesPullInfoConsole | 查询直播间线路与拉流配置详情 |
| 互动与协同 | CreateActivityCouponsConsole / CloseLinkWebCast | 创建卡券互动、关闭网页连麦 |
9.7 OpenAPI 兜底(bytedlive openapi call)
当 control 子命令不覆盖所需能力时(如 9.6 中的高频场景),使用 openapi call 直接调用任意 Action。
bytedlive openapi call --action <ActionName> [--api-version <Version>] \
[--method POST] [--body '...'] [--body-file file.json] [--query '...']Version 解析优先级: 1. 命令行 --api-version 显式指定 2. 静态表 openapiActionVersions.json 中的配置 3. 兜底默认 2020-06-01(serviceDefaultVersion) 4. 响应疑似 Version 错误时 → CLI 自动抓文档 HTML 解析并重试 1 次(可用 --no-doc-version-retry 关闭)
查询 Version:
查静态表:
bytedlive openapi get-version --action <ActionName> --pretty
尝试从文档页拉取:
bytedlive openapi get-version --action <ActionName> --refresh-doc --pretty10. API 字段名规范(强制)
Body 和 Query 字段名必须与火山引擎官方文档完全一致,禁止凭记忆使用。
| 场景 | ❌ 错误 | ✅ 正确 | 说明 |
|---|---|---|---|
| 创建/更新/查询直播间 | ActivityName | Name | 直播间名称字段 |
遇到「参数错误」类报错时:优先检查字段名是否与文档一致,参考 API 文档。
11. OpenAPI 调用失败处理(大模型静默自愈机制)
当调用 OpenAPI 遇到 InvalidActionOrVersion(接口版本错误或找不到)、参数缺失等报错时,千万不要把 JSON 或生涩的报错信息直接抛给普通用户。Agent 必须在后台静默执行以下自愈流程,并在期间用自然语言安抚用户(如:“接口版本有更新,我正在为您匹配最新协议,请稍候...”):
1. 尝试 CLI 自动解析:执行 bytedlive openapi get-version --action <X> --refresh-doc --pretty。 2. 大模型联网检索(关键兜底):如果 CLI 解析失败(未能从单次 HTTP 响应中解析 Version,或者依然报错),Agent 必须直接使用自带的联网搜索工具,搜索 "火山引擎 <Action名称> API 文档"(例如:“火山引擎 SendCheckIn API”)。从最新的官方文档中提取出正确的“接口版本”(如:2023-01-01 或 2023-08-01)。 3. 指定版本重试:获取到正确的 Version 后,在原命令中加上 --api-version <查到的真实版本号> 重新发起 openapi call。 4. 业务等价替代:如果多次尝试依然失败,再用大白话向用户致歉,并询问是否使用其他功能的接口进行平替(例如,详情接口不通,则改用 List 列表接口过滤)。
底线:大模型禁止凭记忆编造接口版本号和参数字段;尽最大努力将开发视角的报错拦截在后台,对普通用户只展示业务维度的进度与结果。
12. 典型工作流示例
示例 0:首次使用(Onboarding)
用户:帮我创建一个直播间
Agent:
1. Skill 首次激活 → 执行 onboarding 流程
2. 检查发现未安装 CLI → 引导安装 `npm i -g bytedlive-cli` 并执行 `bytedlive --version` 验证
3. 执行 bytedlive openapi check-credentials --pretty
4. 失败(无凭证)→ 引导用户本地执行 bytedlive openapi set-credentials
5. 用户回复已配置 → 再次 check-credentials → 验证通过
6. 输出能力概览 + 继续处理"创建直播间"请求示例 1:创建直播间
用户:帮我创建一个明天下午3点开始的直播间,名字叫"产品发布会"
Agent:
1. 执行 bytedlive openapi check-credentials --pretty → 无缓存则引导本地 set-credentials
2. 组装命令:bytedlive control room create --name "产品发布会" --start "2026-04-11 15:00:00"
3. 向用户拟人化确认:"我将为您创建名为『产品发布会』的直播间,时间是明天下午3点,确认执行吗?" → 确认后执行
4. 成功后按模板返回关键信息,并附:
- 控制台地址:https://console.volcengine.com/livesaas/liveManagement/<ActivityId>
- 网页开播地址:https://console.volcengine.com/livesaas/webpush/micromode/<ActivityId>示例 2:禁言某观众
用户:把用户 user_123 禁言
Agent:
1. 确认 activity-id → 若无则先 room list 查询
2. 组装命令:bytedlive control audience mute --activity-id <id> --user-ids user_123
3. 向用户拟人化确认:"请确认是否需要禁言指定用户?" → 用户同意
4. 非黑名单操作,直接执行示例 3:踢出观众(黑名单操作)
用户:把用户 user_456 踢出直播间
Agent:
1. 确认 activity-id
2. 组装命令:bytedlive control audience kick --activity-id <id> --user-ids user_456
3. 向用户拟人化确认:"请确认是否需要踢出用户?" → 用户同意
4. 命中黑名单 → 二次确认:"踢出用户属于高风险操作,可能会影响观众体验。请最后确认一次是否继续?"
5. 用户再次确认 → 执行示例 4:OpenAPI 兜底调用与版本自愈
用户:帮我配置个签到
Agent:
1. control 子命令无此能力 → 走 openapi call (SendCheckIn 等)
2. 执行报错:`InvalidActionOrVersion`
3. 拦截报错,安抚用户:"发现接口版本更新,我正在检索最新配置,请稍候..."
4. 联网搜索 "火山引擎 SendCheckIn API 文档",发现版本是 2023-08-01
5. 组装新命令并确认:"我将为您配置签到,请确认是否执行?"
6. 执行:bytedlive openapi call --action SendCheckIn --api-version 2023-08-01 ...13. 自测
bytedlive control test在已安装 bytedlive CLI 的环境中运行;由命令自动发现并执行匹配的 *.test.js(无可用用例时会跳过并提示)。
Changelog
1.0.5
VERSION与SKILL.mdfront-matter 版本对齐,修复埋点skillVersion不一致。- 自测说明去掉对 Skill 包内不存在目录的硬编码路径,仅保留可执行的
bytedlive control test说明。
1.0.4
control room list的--sort-order支持desc/asc等小写输入,CLI 自动规范为 OpenAPI 要求的Desc/Asc。- 自测说明与
bytedlive control test对齐。
1.0.3
- 启动埋点脚本按 Skill 安装路径自动识别 Agent,避免硬编码
--agent codex导致误报。 - SKILL 启动命令改为
node tools/report_usage.js(无需手动传--agent)。
1.0.0
- 初始版本,提供控播 onboarding、凭证安全、命令路由、OpenAPI 兜底与错误恢复契约。
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
{
"serviceDefaultVersion": "2020-06-01",
"apiOverviewUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"releaseHistoryUrl": "https://www.volcengine.com/docs/3019/129183?lang=zh",
"actions": {
"AnalysisUserBehaviorPeople": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/113770?lang=zh",
"methodHint": "GET",
"riskLevel": "normal"
},
"AnalysisUserBehaviorPeopleV2": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/167658?lang=zh",
"methodHint": "GET",
"riskLevel": "normal"
},
"ActivityLines": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "公开文档未检索到独立接口页,请以 API 参考与线上实际 Action 为准",
"methodHint": "GET",
"riskLevel": "normal"
},
"ActivityLinesPullInfoConsole": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "控制台类接口,文档可能仅内网或控制台侧说明",
"methodHint": "GET",
"riskLevel": "normal"
},
"AddActivityAntidirtAPI": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/124327?lang=zh",
"methodHint": "POST",
"riskLevel": "normal"
},
"BillInstanceCallbackLivesaas": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "计费/实例回调类,多为服务端接收,调用前请核对是否对外 OpenAPI",
"methodHint": "POST",
"riskLevel": "normal"
},
"CanUseAbility": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "未检索到独立文档页,见 API 参考总览",
"methodHint": "GET",
"riskLevel": "normal"
},
"CheckContext": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "未检索到独立文档页,见 API 参考总览",
"methodHint": "POST",
"riskLevel": "normal"
},
"CheckDocLibStorageCapacity": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "未检索到独立文档页,见 API 参考总览",
"methodHint": "GET",
"riskLevel": "normal"
},
"CloseLinkWebCast": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/158215?lang=zh",
"notes": "网页连麦相关,与 CloseLinkWebCast 对应关系请以文档检索或线上为准",
"methodHint": "POST",
"riskLevel": "normal"
},
"CreateActivityAPIV2": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/100053?lang=zh",
"methodHint": "POST",
"riskLevel": "normal"
},
"CreateActivityCouponsConsole": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/1357825?lang=zh",
"notes": "与 CreateActivityCoupons 可能为控制台/OpenAPI 命名差异,以线上 Action 为准",
"methodHint": "POST",
"riskLevel": "normal"
},
"DeleteActivityAPI": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/100054?lang=zh",
"methodHint": "POST",
"riskLevel": "high"
},
"DeleteMediaLibraryVideoAPI": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/912870?lang=zh",
"methodHint": "POST",
"riskLevel": "high"
},
"DeleteUserMessage": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/100078?lang=zh",
"notes": "删除评论类能力亦见 DeleteChatAPI;若线上 Action 为 DeleteUserMessage 请以实际为准",
"methodHint": "POST",
"riskLevel": "high"
},
"EnableProduct": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/1149738?lang=zh",
"notes": "未检索到独立 EnableProduct 页,见商品卡片说明;可能与 EnableProductAPI 并存",
"methodHint": "POST",
"riskLevel": "normal"
},
"EnableProductAPI": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/1149738?lang=zh",
"notes": "未检索到独立页,见商品卡片;上架能力亦可能通过更新商品卡片配置完成",
"methodHint": "POST",
"riskLevel": "normal"
},
"ExplainProduct": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/107752?lang=zh",
"notes": "文档页示例 Action 为 ExplainProductAPI;若控制台仍使用 ExplainProduct 请与 ExplainProductAPI 对照",
"methodHint": "POST",
"riskLevel": "normal"
},
"ExplainProductAPI": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/107752?lang=zh",
"methodHint": "POST",
"riskLevel": "normal"
},
"ForbidLiveChannel": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/2163685?lang=zh",
"methodHint": "POST",
"riskLevel": "high"
},
"GetAccount": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "公开文档未检索到独立 GetAccount 页,见 API 参考总览",
"methodHint": "GET",
"riskLevel": "normal"
},
"GetAccountAPP": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "与 GetAccountApp 可能为同一接口不同命名",
"methodHint": "GET",
"riskLevel": "normal"
},
"GetAccountApp": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "未检索到独立文档页,见 API 参考总览",
"methodHint": "GET",
"riskLevel": "normal"
},
"GetAccountAbilityAmountConsole": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "控制台权益余额类,独立页未检索到",
"methodHint": "GET",
"riskLevel": "normal"
},
"GetAccountCommentAnalysisLLMConsole": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "大模型评论分析控制台类,独立页未检索到",
"methodHint": "GET",
"riskLevel": "normal"
},
"GetAccountConfig": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "未检索到独立文档页,见 API 参考总览",
"methodHint": "GET",
"riskLevel": "normal"
},
"GetAccountProduct": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "账号商品列表;亦可能与 GetActivityProductAPI 等区分账号/直播间维度",
"methodHint": "GET",
"riskLevel": "normal"
},
"GetAccountProductStatisticsThird": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "第三方商品统计,独立页未检索到",
"methodHint": "GET",
"riskLevel": "normal"
},
"GetAccountProductStatus": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/66792?lang=zh",
"notes": "未检索到独立文档页",
"methodHint": "GET",
"riskLevel": "normal"
},
"GetAccountUserTrackData": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/1169974?lang=zh",
"methodHint": "GET",
"riskLevel": "normal"
},
"GetActivityBasicConfigAPI": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/100061?lang=zh"
},
"ListActivityAPI": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/100055?lang=zh"
},
"ListActivityChatAPI": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/105026?lang=zh",
"notes": "直播间评论分类页;单页若与 Action 名不一致请以 API 参考为准"
},
"PollingChatAPI": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/100075?lang=zh"
},
"PresenterChatAPIV2": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/1217286?lang=zh"
},
"SendCustomSystemMessageAPI": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/126052?lang=zh"
},
"SilenceUserAPI": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/105028?lang=zh"
},
"UpdateActivityBasicConfigAPI": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/100060?lang=zh"
},
"UpdateActivityStatusAPI": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/100056?lang=zh"
},
"UpdateActivityUserBanStatus": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/1412599?lang=zh"
},
"UpdateCheckInConfig": {
"version": "2023-08-01",
"docUrl": "https://www.volcengine.com/docs/3019/129183?lang=zh",
"methodHint": "POST",
"riskLevel": "normal",
"notes": "创建或更新签到配置"
},
"SendCheckIn": {
"version": "2023-08-01",
"docUrl": "https://www.volcengine.com/docs/3019/129183?lang=zh",
"methodHint": "POST",
"riskLevel": "normal",
"notes": "发送签到"
},
"StopCheckIn": {
"version": "2023-08-01",
"docUrl": "https://www.volcengine.com/docs/3019/129183?lang=zh",
"methodHint": "POST",
"riskLevel": "normal",
"notes": "停止签到"
},
"WithdrawCheckIn": {
"version": "2023-08-01",
"docUrl": "https://www.volcengine.com/docs/3019/129183?lang=zh",
"methodHint": "POST",
"riskLevel": "normal",
"notes": "撤回签到"
},
"DeleteCheckIn": {
"version": "2023-08-01",
"docUrl": "https://www.volcengine.com/docs/3019/129183?lang=zh",
"methodHint": "POST",
"riskLevel": "high",
"notes": "删除签到"
},
"GetCheckInListAPI": {
"version": "2020-06-01",
"docUrl": "https://www.volcengine.com/docs/3019/129183?lang=zh",
"methodHint": "GET",
"riskLevel": "normal",
"notes": "获取签到列表"
}
}
}
"use strict";
// Keep in sync with cli/lib/agent-normalize.js
/** 埋点 agent 维度固定枚举,与 CLI `--agent` 文档一致 */
const ALLOWED_AGENTS = new Set([
"codex",
"claude-code",
"cursor",
"trae",
"trae-cn",
"openclaw",
"unknown",
]);
const AGENT_ALIASES = {
claudecode: "claude-code",
claude: "claude-code",
};
function normalizeAgentName(input) {
const raw = String(input || "").trim().slice(0, 64);
if (!raw) {
return "unknown";
}
const lower = raw.toLowerCase();
const canonical = AGENT_ALIASES[lower] || lower;
return ALLOWED_AGENTS.has(canonical) ? canonical : "unknown";
}
module.exports = {
ALLOWED_AGENTS,
normalizeAgentName,
};
"use strict";
const path = require("node:path");
const { normalizeAgentName } = require("./agent-normalize");
const AGENT_INSTALL_MARKERS = [
{ marker: `${path.sep}.cursor${path.sep}skills${path.sep}`, agent: "cursor" },
{ marker: `${path.sep}.codex${path.sep}skills${path.sep}`, agent: "codex" },
{ marker: `${path.sep}.claude${path.sep}skills${path.sep}`, agent: "claude-code" },
{ marker: `${path.sep}.trae-cn${path.sep}skills${path.sep}`, agent: "trae-cn" },
{ marker: `${path.sep}.trae${path.sep}skills${path.sep}`, agent: "trae" },
{ marker: `${path.sep}.openclaw${path.sep}skills${path.sep}`, agent: "openclaw" },
];
function detectAgentFromInstallPath(skillRootDir) {
const normalized = path.normalize(skillRootDir);
for (const { marker, agent } of AGENT_INSTALL_MARKERS) {
if (normalized.includes(marker)) {
return agent;
}
}
return "";
}
function resolveReportAgent(options = {}) {
const { cliArg, skillRootDir } = options;
if (cliArg) {
return normalizeAgentName(cliArg);
}
const fromEnv = process.env.BYTEDLIVE_AGENT || process.env.BYTEDLIVE_SKILL_AGENT;
if (fromEnv) {
return normalizeAgentName(fromEnv);
}
const fromPath = detectAgentFromInstallPath(skillRootDir);
if (fromPath) {
return fromPath;
}
return "unknown";
}
module.exports = {
detectAgentFromInstallPath,
normalizeAgentName,
resolveReportAgent,
};
#!/usr/bin/env node
"use strict";
const fs = require("node:fs");
const http = require("node:http");
const https = require("node:https");
const path = require("node:path");
const { resolveReportAgent } = require("./detect-agent");
const SKILL_NAME = "byted-livesaas-master";
const DEFAULT_ENDPOINT = "https://live.byteoc.com/apiservice/skill/track";
const TIMEOUT_MS = 800;
function readVersion() {
try {
return fs.readFileSync(path.join(__dirname, "..", "VERSION"), "utf8").trim();
} catch {
return "";
}
}
function readArg(name) {
const prefix = `--${name}=`;
const inline = process.argv.find((arg) => arg.startsWith(prefix));
if (inline) return inline.slice(prefix.length);
const index = process.argv.indexOf(`--${name}`);
if (index >= 0) return process.argv[index + 1] || "";
return "";
}
function postJson(urlString, payload) {
return new Promise((resolve) => {
let url;
try {
url = new URL(urlString);
} catch {
resolve(false);
return;
}
const body = JSON.stringify(payload);
const client = url.protocol === "http:" ? http : https;
const req = client.request(
url,
{
method: "POST",
timeout: TIMEOUT_MS,
headers: {
"content-type": "application/json",
"content-length": Buffer.byteLength(body),
},
},
(res) => {
res.resume();
res.on("end", () => resolve(res.statusCode >= 200 && res.statusCode < 500));
}
);
req.on("timeout", () => {
req.destroy();
resolve(false);
});
req.on("error", () => resolve(false));
req.end(body);
});
}
async function main() {
if (process.env.BYTEDLIVE_TELEMETRY_DISABLED === "1" || process.env.BYTEDLIVE_TELEMETRY_DISABLED === "true") {
return;
}
await postJson(process.env.BYTEDLIVE_TELEMETRY_ENDPOINT || DEFAULT_ENDPOINT, {
skillName: SKILL_NAME,
agent: resolveReportAgent({
cliArg: readArg("agent"),
skillRootDir: path.join(__dirname, ".."),
}),
source: "skill-start",
action: "skill_use",
eventId: readArg("event-id") || undefined,
skillVersion: readVersion(),
});
}
main().catch(() => {});
1.0.5
Related skills
FAQ
How are credentials configured?
The user runs bytedlive openapi set-credentials locally with their AK/SK; keys are never pasted into the conversation.
What is not covered?
Streaming/encoding problems, WebSDK integration, billing/plan management, and non-live products like VOD or RTC.