群聊消息
用于通过 Live APIs 运行群聊房间的管理员客户端收发消息的参考,包括字段、错误和轮次结果。
这些消息只存在于一个使用以下方式创建的房间中 group_chat: true。它们通过该房间的 LiveKit 数据通道传输,并与文档中记录的消息一起传输于 客户端到服务器的消息 和 服务器到客户端的消息 页面上。只有房间中的人类参与者可以发送 group-address;本页称该参与者为 主持人。当使用以下方式创建时,一个房间可以容纳不止一名人类 max_num_participants ,超过其默认的 1;额外的人类按中所述加入 使用多角色会话。封装约定遵循 消息术语表,但有两个不同:群聊命令还携带一个顶层的 label 和 id,并且 turn-complete 到达时没有顶层的 label 字段开始的类型。
你发送的命令
group-address
将房间定向给一个回合。只有主持人可以发送它,而且只能通过 LiveKit 数据通道发送。
{
"label": "rtvi-ai",
"type": "group-address",
"id": "turn-0001",
"data": {
"room_session_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
"mode": "all",
"expected_route_epoch": 0,
"text": "请每个角色用一句话介绍自己。"
}
}label
字符串
否
常规 RTVI 标签, "rtvi-ai"。服务器会忽略它;发送它只是为了与其他客户端消息保持一致。
id
字符串
是
命令 id,1–128 个字符。在该房间内你发送的每个命令中必须唯一; group-address, interaction-target,并且 character-roster-update 共享同一个 id 空间。
data.room_session_id
UUID
是
房间,来自 /connect 响应。
data.mode
字符串
是
定向模式: "all", "tagged",或者 "open"。请参见下方表格。
data.target_membership_ids
UUID[]
"tagged" 仅限
至少一个在线 membership_id,且不含重复。若为 "all" 和 "open" 则省略它——使用任一模式发送的列表都会被忽略,而该回合仍会定向到房间中的每个实例。
data.expected_route_epoch
整数
是
你持有的最新 route_epoch ,来自 /connect 或来自 extras.route_epoch 上一次 group-address, interaction-target,或者 character-roster-update 响应的结果。移除当前活动实例会提升该纪元。
data.text
字符串
是
主持人的消息。
定向模式
mode
被指向的人
必须回复
"all"
房间中的每个角色实例。
是。拒绝会被报告为失败。
"tagged"
仅限列在中的实例 target_membership_ids.
是。拒绝会被报告为失败。
"open"
房间中的每个角色实例。
否。实例可以拒绝,此时会被报告为已通过。
服务器响应额外字段
服务器对每个 group-address 都只返回一个 server-response 携带 event_type: "group-address"。对于它接受的命令,该响应会在所有被定向的实例完成后到达;被拒绝的命令会立即以 status: "error"进行回复。一个回合还会产生 server-response 你未发送的消息,其中带有 event_type "context-update" 或 "user_text_message",每个被定向实例可能各一条;忽略任何 server-response 其 event_type 不是你自己的命令之一的消息。对于 status: "success", extras 携带:
command_id
字符串
该 id 从请求中回显。
room_session_id
UUID
该房间。
mode
字符串
本次回合使用的定向模式。
route_epoch
整数
房间当前的纪元。将此值作为 expected_route_epoch 发送到下一条命令中。
target_membership_ids
UUID[]
本次回合定向到的实例。
answered_membership_ids
UUID[]
产生回复的实例。
passed_membership_ids
UUID[]
拒绝的实例。只有一个 "open" 回合会在这里产生条目。
failed_membership_ids
UUID[]
未产生回复的实例。超时会在这里报告。
summary.turn_id
字符串
回合标识符,等于 command_id.
summary.addressed
整数
被定向的实例数量。
summary.answered
整数
回复的实例数量。
summary.passed
整数
拒绝的实例数量。
summary.failed
整数
未回复的实例数量。
summary.cancelled
布尔值
存在于每个摘要中。取消无法触达,因此该值始终为 false.
summary.route_epoch
整数
回合开始时捕获的路由纪元。
status: "success" 表示回合已结束,而不是表示有人回复了。即使回合中每个实例都失败或超时,仍会返回 成功。请阅读 failed_membership_ids 以了解发生了什么。
在 status: "error", extras 携带 代码。房间本身抛出的错误—— stale_route_epoch, invalid_target_membership, duplicate_target_membership, empty_target_set 在一个 "all" 或 "open" 回合中, turn_in_progress, turn_wait_timeout,并且 command_id_conflict ——也携带 command_id, room_session_id, active_membership_id,并且 route_epoch。在命令到达房间之前就被拒绝的错误—— not_roster_room, not_group_chat_room, unauthorized_sender, invalid_command, wrong_room, invalid_route_epoch, empty_message, empty_target_set 在一个 "tagged" 回合中,以及 coordinator_unavailable ——只携带 代码 ,因此要把它们和你尚未完成的命令关联,而不是和 extras.command_id。失败的 group-address-part 帧会以 代码 和 command_id回复。意外的服务器端故障会以 status: "error" 和一个 消息 但没有 extras,因此请读取 extras.code 带有可选访问并回退到 消息.
错误代码
代码
当
该怎么做
not_roster_room
该房间是使用以下方式创建的 character_id来表示移除,而不是 characters.
使用以下方式创建该房间 characters.
not_group_chat_room
该房间是在没有 group_chat: true.
新建一个带有 group_chat: true.
unauthorized_sender
发送者不是该房间中的人类参与者。
从人类参与者的连接发送该命令。
invalid_command
在一个 group-address, id 缺失或超过 128 个字符时, data 不是对象,或者 mode 不是这三个值之一;或者一个 group-address-part 帧格式错误。
修正消息并用新的 id.
wrong_room
data.room_session_id 不是该房间。
使用 room_session_id 来自 /connect.
invalid_route_epoch
expected_route_epoch 不是整数。
发送整数。
stale_route_epoch
expected_route_epoch 与房间的纪元不匹配。
从 extras.route_epoch 从此响应中移除并用新的 id.
empty_message
文本 为空。
发送文本。
empty_target_set
"tagged" 是在没有目标的情况下发送的,或者 "all" / "open" 发送到了一个没有在线实例的房间。
至少列出一个 membership_id,或者等待某个实例变为就绪。
invalid_target_membership
目标不是该房间中的在线 membership_id ,或者不是 UUID。
使用 membership_id 中的值, /connect, bot-ready,或者 roster 响应。
duplicate_target_membership
相同的 id 在 target_membership_ids.
移除重复项。
turn_in_progress
由于有一个回合正在运行,你的命令被立即拒绝。
等待该 turn 的 server-response,然后再重新发送。
turn_wait_timeout
你的命令等待了正在运行的回合,但该回合在回合超时加上一个很短的余量内仍未结束,默认大约两分钟。
重新发送。
command_id_conflict
该 id 被以不同内容重复使用。
使用新的 id.
coordinator_unavailable
该房间已不再可服务。
创建一个新房间。
幂等性
重新发送相同的 id 且内容相同会被静默接受,不会产生第二个响应。不要等待第二个响应;请依赖第一个响应。重新发送相同的 id 则会被拒绝,并返回 command_id_conflict.
一次只进行一个回合
一个房间一次只运行一个回合。在回合运行时发送第二个 group-address 会被以 turn_in_progress 拒绝,并且不会被缓存,因此请在该回合的之后重试 server-response. interaction-target 和 character-roster-update 在回合期间也会以相同代码被拒绝。
group-address-part
携带一个 group-address 的帧,而该帧太大,无法一次发送完。LiveKit 数据通道拒绝超过 15,360 字节的消息。
label
字符串
否
常规 RTVI 标签, "rtvi-ai"。服务器会忽略它。
id
字符串
是
该 group-address 正在发送中的命令 id,1–128 个字符。每一帧都相同。
data.command_id
字符串
否
当存在时,它必须等于 id.
data.index
整数
是
此帧的从零开始的位置,来自 0 设置为 count - 1.
data.count
整数
是
帧的总数, 1 设置为 64。每一帧都相同。
data.payload
字符串
是
完整 JSON 的一个 base64 切片。 group-address JSON。
分块规则
先把完整的 JSON 消息进行一次 base64 编码,然后将该字符串拆分到各个帧中;每个
group-addresspayload都是其中的一段。服务器按顺序拼接这些切片,并只解码一次。
index。只有最后一段可以携带
=填充。服务器在解码前会先拼接切片,因此除结尾之外任何地方出现填充都会导致整个命令失败。可以在任意位置拆分编码字符串;服务器会原样重建它。切勿分别对每一帧单独进行 base64 编码,因为那会把填充放在中间并导致整个命令失败。单个命令的 base64 载荷总计最多 1 MiB,约合 768 KiB 的
group-addressJSON。格式错误或超大帧会使该命令失败,错误为
event_type: "group-address",status: "error",并且code: "invalid_command"。不过有两种失败是静默的:如果某帧的id缺失或超过 128 个字符,则该帧会被丢弃,因为没有可用于关联回复的内容;如果一个命令在首帧后的 1 分钟内仍未完成,则这条部分送达的命令会被放弃。在这两种情况下,回合都不会结束,因此请在客户端侧超时,并及时发送一个命令的所有帧。重新组装后的消息会被按完全相同的方式处理,就像一个
group-address随该id.
你接收的消息
turn-complete
结束一个群聊回合并报告其结果。 turn-complete 报告整个群聊回合; bot-turn-completed 是按角色区分的,并且在群聊房间中保持不变。
room_session_id
UUID
该房间。
command_id
字符串
该 id 的 group-address 开启该回合的。
mode
字符串
本次回合使用的定向模式。
addressed_membership_ids
UUID[]
本次回合定向到的实例。命名为 target_membership_ids 在 server-response extras。
answered_membership_ids
UUID[]
产生回复的实例。
passed_membership_ids
UUID[]
拒绝的实例。只有一个 "open" 回合会在这里产生条目。
failed_membership_ids
UUID[]
未产生回复的实例。未在回合超时内完成的实例会列在这里。
turn_id
字符串
回合标识符,等于 command_id.
addressed
整数
被定向的实例数量。
answered
整数
回复的实例数量。
passed
整数
拒绝的实例数量。
failed
整数
未回复的实例数量。
cancelled
布尔值
出现在每个 turn-complete中。取消无法触达,因此该值始终为 false.
route_epoch
整数
回合开始时捕获的路由纪元。
此消息的四个属性会影响客户端如何消费它:
turn-complete没有顶层的label,不同于大多数服务器消息。不要根据label.turn-complete对传入消息进行过滤;每个回合最多发送一次,不论房间中有多少个角色实例。它通过某个实例的连接发布,且不会重试,因此请把server-response视为回合可靠结束。其data还可能携带发布该消息的实例的身份字段;忽略它们并读取列表。turn-complete可能会在实例最后一个bot-llm-textdelta 之前以及在server-response之前到达。之后继续接受一小段宽限期内的回复文本——实际上 1 到 2 秒就足够。route_epoch这里指的是回合的快照,而不是下一次要发送的值。发送extras.route_epoch来自server-response作为下一个expected_route_epoch.
按角色消息上的身份字段
在使用以下方式创建的房间中的服务器消息 characters 数组(每个群聊房间都是如此)携带六个身份字段,用来将它们与某个角色实例关联: room_session_id, membership_id, character_id, character_session_id, participant_identity,并且 is_initial。这些字段的位置取决于消息的形状。已经携带 data 对象的消息会在该对象内部接收它们。扁平消息会在为它们创建的 data 对象中接收它们,从而产生一个嵌套的 data.data 路径。
data
data
data
bot-ready
data.about,映射在 data
character-status
data
character-removed
data
嵌套的 data 对象
嵌套的 data 对象
嵌套的 data 对象;有用的字段保留在 extras
每个实例都会将其回复作为普通 bot-llm-text 消息流式发送。按 data.membership_id. bot-llm-stopped 来标识该回复。
不要也消费 bot-transcription;它重复了相同的回复文本。
一个拒绝 "open" 回合会用 llm-no-response 和 reason: "abstain"来宣布它。由于该消息是扁平的,其身份字段位于一个嵌套的 data 对象下:
turn-complete 才是权威,而不是这条消息。如果实例在拒绝之前流式发送了任何可见文本,那么以回复为准,该实例会列在 answered_membership_ids中。实例也可能列在 passed_membership_ids 中而从未发送过 llm-no-response中。将 llm-no-response 视为提示,并根据 turn-complete 列表来确定结果。
群聊房间中的 bot-ready
bot-ready 是中所描述的消息 映射每个角色实例。在群聊房间中,它的 data.about 对象通常除了那里记录的字段外还会携带一个字段: :即要显示给该实例的名称。该字段尽力提供;若不存在,则回退到该 membership 的,用于显示该实例的名称。该字段只是尽力而为。若它缺失,则回退到该实例的 :即要显示给该实例的名称。该字段尽力提供;若不存在,则回退到该 membership 的 上的 /connect roster 条目,该条目携带的是角色的纯名称,不含下一步所述的房间唯一后缀,因此请自行消歧回退值。
显示名称在房间内会被设为唯一:名为 Ada 的第二个实例会被赋予显示名称 Ada (2)。一个 character-status 消息带有 status: "ready" 在其 data 对象中以平面形式携带相同字段。
相关页面
构建群聊使用多角色会话客户端到服务器消息服务器到客户端消息最后更新于
这有帮助吗?