呼叫等待转接与AI转人工
约 12892 字大约 43 分钟
2026-10-16
本页包含已接线核心流程及可选扩展;具体子能力必须按设备、平台与用户授权求交集。参见支持范围、场景索引和命令手册。图中S编号只用于本文定位,不放入实际JSON。
前置条件
设备主动呼叫通过sessionCreate.targetParty指定授权用户或设备;不会仅凭可见设备ID得到拨打权限。展示取消、保持、转接与转人工子流程,媒体建立复用S06。
设备→用户、设备→设备、应用→设备使用同一呼叫组和独立端会话腿。已忙可拒绝或waiting,不自动hold旧通话;用户接听新来电才先hold旧通话并切焦点。挂断新通话也要按S18规则恢复旧通话。cancel仅取消尚未接通的组,若接听已先提交则返回409,调用者明确再hangup。这是控制请求失败,不是原呼叫失败:原会话腿、忙线所有权与媒体不因该拒绝被关闭;失败字段及原token去重顺序见callState。
D/D2是不同设备参与端,A是应用端,P是平台和媒体节点。各端分别使用鉴权Topic/登录态,不能冒用另一端身份。基础会话与媒体协商见S01/S06,复用时保留本场景sessionId并独立分配密钥和token。
正常设备转接中,D是转接发起方,成功后只结束D原会话腿;D2保留原会话腿与媒体端点,最终与新候选D3通话。候选真正接听、ICE/DTLS连通及匹配mediaState前,D↔D2原媒体不切换;拒接、候选取消或超时只失败本次操作,保留原呼叫、忙线和媒体。此语义不套用于下方独立AI转人工分支。
AI转人工示例中,原D的s-ai始终属于AI;s13-human-local是D的新人工会话腿,s13-human仅属于D3,二者同属s13-ai-human-group。这些由平台在原意图账本中一次分配,并通过escalate条件关联字段告知D,不能由设备猜测或自报。原AI能力与双方人际能力必须真实同时支持;当前独立AI/人际客户端不因此设计自动具备组合能力。
第三屏障还要求D已实际声明microphone/speaker整组焦点能力、原AI确有对应完整租约和唯一共享采集/播放驱动。普通独立桌面末端的speaker/display能力不能替代整组能力;本协议已新增C++共享宿主、HumanVoice适配及浏览器独立输入/输出门控,但真实组合验收仍未完成,不能把单测回执当实际交接。未声明或未取得完整资源时明确拒绝,不发虚构整组回执。原租约、原用户意图、全局revision和两腿关联必须在平台及设备可信账本存在;有Peer不等于有采集授权,priority=call也不自动抢原租约。
下方AI示例假设s-ai已消耗eventSeq至100、其真实整组租约为ai-conversation-focus、设备全局资源修订号为10;这些须来自原已确认账本与实际驱动,不能由设备猜测或初始化补造。成功分支M65消耗旧AI事件101,M46为102、M47为103;新人际本端腿M67为事件2、M55为3。拒接分支未执行M65时M58仍为101;若已发送M65则M58须用下一实际事件号,恢复分支已发送M70时须大于102,不重置共享水位。失败与成功分支互斥,不把所有示例串为一次执行。绝对到期、SDP和资源标识均为占位示例,不是可连接凭据;实际邀请截止为首次45秒候选期限、原会话/授权期限与邀请30秒上限的最早值,不因accept、重投或新token关联而延长。
完整时序
已完成AI转人工后的人工挂断
上方完整时序图末尾的M75–82为此分支;逐条JSON和应答关联见下方索引,不另定义一份字段契约。
首次通知/释放总截止为min(首次时点+10秒, 原请求总预算, Owner/两腿/两连接租约, 人工业务截止),投递和首次ACK共用,不因重试重置。平台Peer及忙线只在原提交已确认后停止;SQL未知的后继确认仍核原写集。原已完成End操作固定保留600秒,只允许原主体/会话/token/不可变请求精确读回,以及原已完成释放ACK字节的只读确认;不是允许首次迟到释放的新窗口。未确认资源保持unknown,无权恢复旧AI或另一腿。
报文索引
编号按图阅读;编号保留历史引用,不要求数值连续。字段定义以命令链接为准。
| 编号 | 发送→接收 | Topic/接口 | 方法及契约 | 应答/等待 | 状态或作用 |
|---|---|---|---|---|---|
| S13-M01 | D→P | SIG↑ | sessionCreate | 对应应答见命令;10秒受理,媒体协商15秒 | |
| S13-M02 | P→D | SIG↓ | sessionCreated | 应答/状态事件;不等待ACK | |
| S13-M22 | P→D2 | SIG↓ | sessionInvite | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M03 | D→P | SIG↑ | callControl | callState;10秒受理,媒体协商15秒 | |
| S13-M04 | P→D | SIG↓ | callState | 应答/状态事件;不等待ACK | |
| S13-M05 | P→D | SIG↓ | sessionEnded | 应答/状态事件;不等待ACK | |
| S13-M23 | D2→P | SIG↑ | sessionAccept | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S13-M24 | P→D2 | SIG↓ | requestAck | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M06 | D→P | SIG↑ | mediaOffer | 对应应答见命令;10秒受理,媒体协商15秒 | |
| S13-M07 | P→D | SIG↓ | mediaAnswer | 应答/状态事件;不等待ACK | |
| S13-M08 | D→P | SIG↑ | mediaState | 对应应答见命令;10秒受理,媒体协商15秒 | |
| S13-M09 | P→D | SIG↓ | requestAck | 应答/状态事件;不等待ACK | |
| S13-M25 | D2→P | SIG↑ | mediaOffer | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S13-M26 | P→D2 | SIG↓ | mediaAnswer | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M27 | D2→P | SIG↑ | mediaState | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S13-M28 | P→D2 | SIG↓ | requestAck | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M29 | P→D2 | SIG↓ | sessionEstablished | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M10 | P→D | SIG↓ | sessionEstablished | 应答/状态事件;不等待ACK | |
| S13-M11 | D→P | SIG↑ | callControl | callState;10秒受理,媒体协商15秒 | |
| S13-M12 | P→D | SIG↓ | callState | 应答/状态事件;不等待ACK | |
| S13-M13 | D→P | SIG↑ | callControl | callState;10秒受理,媒体协商15秒 | |
| S13-M14 | P→D | SIG↓ | callState | 应答/状态事件;不等待ACK | |
| S13-M15 | D→P | SIG↑ | callControl | callState;10秒受理,媒体协商15秒 | |
| S13-M16 | P→D | SIG↓ | callState | 应答/状态事件;不等待ACK | |
| S13-M30 | P→D3 | SIG↓ | sessionInvite | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M31 | D3→P | SIG↑ | sessionAccept | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S13-M32 | P→D3 | SIG↓ | requestAck | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M33 | D3→P | SIG↑ | mediaOffer | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S13-M34 | P→D3 | SIG↓ | mediaAnswer | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M35 | D3→P | SIG↑ | mediaState | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S13-M36 | P→D3 | SIG↓ | requestAck | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M37 | P→D3 | SIG↓ | sessionEstablished | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M17 | P→D | SIG↓ | callState | 应答/状态事件;不等待ACK | |
| S13-M18 | P→D | SIG↓ | sessionEnded | 应答/状态事件;不等待ACK | |
| S13-M19 | P→D | SIG↓ | callState | 应答/状态事件;不等待ACK | |
| S13-M20 | D→P | SIG↑ | callControl | callState;10秒受理,媒体协商15秒 | |
| S13-M21 | P→D | SIG↓ | callState | 应答/状态事件;不等待ACK | |
| S13-M38 | P→D3 | SIG↓ | sessionInvite | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M48 | P→D | SIG↓ | sessionInvite | M49或M63;30秒或原截止更早 | 设计:关联D新人工腿,不抢占AI |
| S13-M56 | D3→P | SIG↑ | sessionReject | M57;10秒受理 | 设计:拒人工候选,不结束AI |
| S13-M57 | P→D3 | SIG↓ | requestAck | 无ACK | 确认拒接 |
| S13-M63 | D→P | SIG↑ | sessionReject | M64;10秒受理 | 设计:本端拒新腿 |
| S13-M64 | P→D | SIG↓ | requestAck | 无ACK | 确认本端拒接 |
| S13-M61 | D→P | SIG↑ | callControl | M62;10秒受理 | 设计:原AI作用域撤原候选 |
| S13-M62 | P→D | SIG↓ | callState | 无ACK | active/candidateCancelled,保AI |
| S13-M39 | D3→P | SIG↑ | sessionAccept | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S13-M40 | P→D3 | SIG↓ | requestAck | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M49 | D→P | SIG↑ | sessionAccept | M50;10秒受理 | 设计:仅接听本端新腿 |
| S13-M50 | P→D | SIG↓ | requestAck | 无ACK | negotiating,不是切换完成 |
| S13-M41 | D3→P | SIG↑ | mediaOffer | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S13-M42 | P→D3 | SIG↓ | mediaAnswer | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M43 | D3→P | SIG↑ | mediaState | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S13-M44 | P→D3 | SIG↓ | requestAck | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M51 | D→P | SIG↑ | mediaOffer | M52;原媒体协商15秒 | 设计:独立新Peer与代次 |
| S13-M52 | P→D | SIG↓ | mediaAnswer | 无ACK | 设计:SDP完成不等于连通 |
| S13-M53 | D→P | SIG↑ | mediaState | M54;10秒受理 | 设计:真实ICE/DTLS事实 |
| S13-M54 | P→D | SIG↓ | requestAck | 无ACK | 设计:单腿就绪仍保持AI |
| S13-M65 | P→D | SIG↓ | focusControl | M66或M72;原授权/候选截止约束 | 设计:原AI实际完整组suspend,不是结束AI |
| S13-M66 | D→P | SIG↑ | focusState | 无ACK;原token关联 | 设计:原组实际suspended,revision=11 |
| S13-M67 | P→D | SIG↓ | focusControl | M68或M69;不得续原期限 | 设计:原本端新人际腿取得同一物理完整组 |
| S13-M68 | D→P | SIG↑ | focusState | 无ACK;平台仍须复核并持久提交 | 设计:实际acquired,revision=12,不等于平台提交 |
| S13-M45 | P→D3 | SIG↓ | sessionEstablished | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M55 | P→D | SIG↓ | sessionEstablished | 无ACK | 设计:实际整组回执与平台路由持久提交后的最终确认 |
| S13-M46 | P→D | SIG↓ | callState | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M47 | P→D | SIG↓ | sessionEnded | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S13-M69 | D→P | SIG↑ | focusState | 无ACK;原M67关联 | 设计:明确未取得新人际组,拒绝不推进revision |
| S13-M70 | P→D | SIG↓ | focusControl | M71;原AI仍授权且路由明确未提交 | 设计:原组restore补偿,不创建新租约或续旧许可 |
| S13-M71 | D→P | SIG↑ | focusState | 无ACK;原token关联 | 设计:原组实际restored才呈现AI采集恢复 |
| S13-M72 | D→P | SIG↑ | focusState | 无ACK;原M65关联 | 设计:suspend明确未执行,原归属保持 |
| S13-M58 | P→D | SIG↓ | callState | 无ACK;原候选最多45秒 | 设计:失败只作用原escalate操作 |
| S13-M59 | P→D3 | SIG↓ | sessionEnded | 无ACK | 设计:结束人工候选腿 |
| S13-M60 | P→D | SIG↓ | sessionEnded | 无ACK | 设计:仅结束D新人工腿 |
| S13-M73 | P→D3 | MSG↓ | contextSnapshot | M74;原expiresAt内有界重试 | 仅原已消费授权及当前实际人工remote腿;正式投递纵切待验 |
| S13-M74 | D3→P | MSG↑ | contextSnapshotAck | 不再次ACK | 完整实际留存,不等于阅读/播放 |
| S13-M75 | D→P | SIG↑ | sessionEnd | M76;原截止内最多10秒 | 新增接线待端云验收;结束当前人工腿及关联对端 |
| S13-M76 | P→D | SIG↓ | sessionEnded | 原token/code应答,不再ACK | 持久终态,不等于实际释放 |
| S13-M77 | P→D3 | SIG↓ | sessionEnded | 本腿eventSeq,无ACK | 对端终态,不关闭唯一连接绕过原release |
| S13-M78 | P→D | SIG↓ | focusControl | M79;原挂断截止,不重新起算 | 当前本腿原完整组释放 |
| S13-M79 | D→P | SIG↑ | focusState | 无二次ACK | 双端实际false且原控制精确关联才回released |
| S13-M80 | P→D3 | SIG↓ | focusControl | M81;与M78相同原截止 | 对端原完整组释放,不能借本端回执替代 |
| S13-M81 | D3→P | SIG↑ | focusState | 无二次ACK | 对端原实际释放独立证明 |
| S13-M82 | P→D | SIG↓ | sessionEnded | 无ACK;原完成操作保留期内 | 精确重放M76原字节,不续期、不发新操作 |
逐条JSON
S13-M01 · sessionCreate
{
"msgToken": "s13-7",
"method": "sessionCreate",
"params": {
"purpose": "humanCall",
"transport": "webrtc",
"tracks": [
{
"trackId": "mic",
"kind": "audio",
"sourceId": "mic",
"sourceType": "microphone",
"direction": "sendonly",
"codec": "opus",
"state": "requested"
},
{
"trackId": "speaker",
"kind": "audio",
"sourceId": "remote-voice",
"direction": "recvonly",
"codec": "opus",
"state": "requested"
}
],
"targetParty": {
"kind": "device",
"id": "p13:original-device-b"
},
"callType": "voice",
"callPolicy": {
"floor": "shared",
"busy": "waiting"
}
}
}S13-M02 · sessionCreated
{
"msgToken": "s13-7",
"method": "sessionCreated",
"sessionId": "s13-session",
"data": {
"state": "negotiating",
"selected": {
"transport": "webrtc"
},
"tracks": [
{
"trackId": "mic",
"kind": "audio",
"sourceId": "mic",
"sourceType": "microphone",
"direction": "sendonly",
"codec": "opus",
"state": "requested"
},
{
"trackId": "speaker",
"kind": "audio",
"sourceId": "remote-voice",
"direction": "recvonly",
"codec": "opus",
"state": "requested"
}
],
"callGroupId": "cg13"
},
"code": 200
}S13-M22 · sessionInvite
{
"msgToken": "s13-s13-remote-invite",
"method": "sessionInvite",
"sessionId": "s13-remote",
"eventSeq": 1,
"params": {
"purpose": "humanCall",
"transport": "webrtc",
"admission": "accept",
"tracks": [
{
"trackId": "voice",
"kind": "audio",
"sourceId": "microphone",
"sourceType": "microphone",
"direction": "sendrecv",
"codec": "opus",
"state": "requested"
}
],
"expiresAt": 1900000000000,
"callType": "voice",
"callGroupId": "cg13"
}
}S13-M03 · callControl
{
"msgToken": "s13-8",
"method": "callControl",
"sessionId": "s13-session",
"params": {
"operation": "cancel",
"expectedRevision": 0
}
}S13-M04 · callState
{
"msgToken": "s13-8",
"method": "callState",
"sessionId": "s13-session",
"data": {
"state": "cancelled",
"revision": 1,
"reason": "callerCancelled"
},
"code": 200
}S13-M05 · sessionEnded
{
"msgToken": "s13-9",
"method": "sessionEnded",
"sessionId": "s13-session",
"data": {
"state": "ended",
"reason": "callerCancelled"
},
"eventSeq": 1
}S13-M23 · sessionAccept
{
"msgToken": "s13-s13-remote-invite",
"method": "sessionAccept",
"sessionId": "s13-remote",
"params": {
"acceptedTracks": [
"voice"
]
}
}S13-M24 · requestAck
{
"msgToken": "s13-s13-remote-invite",
"method": "requestAck",
"sessionId": "s13-remote",
"code": 200,
"data": {
"requestMethod": "sessionAccept",
"result": {
"state": "negotiating"
}
}
}S13-M06 · mediaOffer
{
"msgToken": "s13-10",
"method": "mediaOffer",
"sessionId": "s13-session",
"params": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S13-M07 · mediaAnswer
{
"msgToken": "s13-10",
"method": "mediaAnswer",
"sessionId": "s13-session",
"data": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
},
"code": 200
}S13-M08 · mediaState
{
"msgToken": "s13-11",
"method": "mediaState",
"sessionId": "s13-session",
"params": {
"mediaRevision": 1,
"state": "connected"
}
}S13-M09 · requestAck
{
"msgToken": "s13-11",
"method": "requestAck",
"sessionId": "s13-session",
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 1,
"state": "connected"
}
},
"code": 200
}S13-M25 · mediaOffer
{
"msgToken": "s13-s13-remote-offer",
"method": "mediaOffer",
"sessionId": "s13-remote",
"params": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S13-M26 · mediaAnswer
{
"msgToken": "s13-s13-remote-offer",
"method": "mediaAnswer",
"sessionId": "s13-remote",
"code": 200,
"data": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
}
}S13-M27 · mediaState
{
"msgToken": "s13-s13-remote-connected",
"method": "mediaState",
"sessionId": "s13-remote",
"params": {
"mediaRevision": 1,
"state": "connected"
}
}S13-M28 · requestAck
{
"msgToken": "s13-s13-remote-connected",
"method": "requestAck",
"sessionId": "s13-remote",
"code": 200,
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 1,
"state": "connected"
}
}
}S13-M29 · sessionEstablished
{
"msgToken": "s13-s13-remote-established",
"method": "sessionEstablished",
"sessionId": "s13-remote",
"eventSeq": 2,
"data": {
"state": "established",
"mediaRevision": 1
}
}S13-M10 · sessionEstablished
{
"msgToken": "s13-12",
"method": "sessionEstablished",
"sessionId": "s13-session",
"data": {
"state": "established",
"mediaRevision": 1
},
"eventSeq": 2
}S13-M11 · callControl
{
"msgToken": "s13-13",
"method": "callControl",
"sessionId": "s13-session",
"params": {
"operation": "hold",
"expectedRevision": 0
}
}S13-M12 · callState
{
"msgToken": "s13-13",
"method": "callState",
"sessionId": "s13-session",
"data": {
"state": "held",
"revision": 1
},
"code": 200
}S13-M13 · callControl
{
"msgToken": "s13-14",
"method": "callControl",
"sessionId": "s13-session",
"params": {
"operation": "resume",
"expectedRevision": 1
}
}S13-M14 · callState
{
"msgToken": "s13-14",
"method": "callState",
"sessionId": "s13-session",
"data": {
"state": "active",
"revision": 2
},
"code": 200
}S13-M15 · callControl
{
"msgToken": "s13-15",
"method": "callControl",
"sessionId": "s13-session",
"params": {
"operation": "transfer",
"expectedRevision": 2,
"target": {
"kind": "device",
"id": "p13:candidate-device-c"
}
}
}S13-M16 · callState
{
"msgToken": "s13-15",
"method": "callState",
"sessionId": "s13-session",
"data": {
"state": "transferring",
"revision": 3,
"candidateSessionId": "s13-candidate"
},
"code": 200
}S13-M30 · sessionInvite
{
"msgToken": "s13-s13-candidate-invite",
"method": "sessionInvite",
"sessionId": "s13-candidate",
"eventSeq": 1,
"params": {
"purpose": "humanCall",
"transport": "webrtc",
"admission": "accept",
"tracks": [
{
"trackId": "voice",
"kind": "audio",
"sourceId": "microphone",
"sourceType": "microphone",
"direction": "sendrecv",
"codec": "opus",
"state": "requested"
}
],
"expiresAt": 1900000000000,
"callType": "voice",
"callGroupId": "cg13"
}
}S13-M31 · sessionAccept
{
"msgToken": "s13-s13-candidate-invite",
"method": "sessionAccept",
"sessionId": "s13-candidate",
"params": {
"acceptedTracks": [
"voice"
]
}
}S13-M32 · requestAck
{
"msgToken": "s13-s13-candidate-invite",
"method": "requestAck",
"sessionId": "s13-candidate",
"code": 200,
"data": {
"requestMethod": "sessionAccept",
"result": {
"state": "negotiating"
}
}
}S13-M33 · mediaOffer
{
"msgToken": "s13-s13-candidate-offer",
"method": "mediaOffer",
"sessionId": "s13-candidate",
"params": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S13-M34 · mediaAnswer
{
"msgToken": "s13-s13-candidate-offer",
"method": "mediaAnswer",
"sessionId": "s13-candidate",
"code": 200,
"data": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
}
}S13-M35 · mediaState
{
"msgToken": "s13-s13-candidate-connected",
"method": "mediaState",
"sessionId": "s13-candidate",
"params": {
"mediaRevision": 1,
"state": "connected"
}
}S13-M36 · requestAck
{
"msgToken": "s13-s13-candidate-connected",
"method": "requestAck",
"sessionId": "s13-candidate",
"code": 200,
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 1,
"state": "connected"
}
}
}S13-M37 · sessionEstablished
{
"msgToken": "s13-s13-candidate-established",
"method": "sessionEstablished",
"sessionId": "s13-candidate",
"eventSeq": 2,
"data": {
"state": "established",
"mediaRevision": 1
}
}S13-M17 · callState
{
"msgToken": "s13-16",
"method": "callState",
"sessionId": "s13-session",
"data": {
"state": "transferred",
"revision": 4,
"candidateSessionId": "s13-candidate",
"requestToken": "s13-15"
},
"eventSeq": 3
}S13-M18 · sessionEnded
{
"msgToken": "s13-17",
"method": "sessionEnded",
"sessionId": "s13-session",
"data": {
"state": "ended",
"reason": "transferred"
},
"eventSeq": 4
}S13-M19 · callState
{
"msgToken": "s13-18",
"method": "callState",
"sessionId": "s13-session",
"data": {
"state": "failed",
"revision": 4,
"candidateSessionId": "s13-candidate",
"reason": "transferRejected",
"requestToken": "s13-15"
},
"eventSeq": 5
}本事件的failed是原requestToken关联的转接操作终态,不是原呼叫组或任一原会话腿的终态;不得随后结束D/D2,原实际媒体与忙线保持。候选拒绝、30秒未接听、首次45秒总窗到期、媒体失败、权限撤销或修订变化均只撤该候选代次;已分配时可携带原candidateSessionId,未分配不能编造ID。及时接听仅切换至原总窗剩余预算,原邀请字节及两项截止不因重投续期;旧邀请计时回调不得撤已接听候选。
发起者撤销候选(不改变原M01至M47编号)
在M16之后、候选实际媒体就绪原子切换之前,D可沿本端s13-session发送以下取消;平台必须核原主体/原转接账本/candidate代次及expectedRevision。此分支只结束候选D3,原D↔D2实际媒体继续;不执行M17/M18,不向原腿发送sessionEnded。不带candidateSessionId的已接通cancel仍按409 invalidState拒绝。
{
"msgToken": "s13-candidate-cancel",
"method": "callControl",
"sessionId": "s13-session",
"params": {
"operation": "cancel",
"expectedRevision": 3,
"candidateSessionId": "s13-candidate"
}
}{
"msgToken": "s13-candidate-cancel",
"method": "callState",
"sessionId": "s13-session",
"code": 200,
"data": {
"state": "active",
"revision": 4,
"candidateSessionId": "s13-candidate",
"reason": "candidateCancelled"
}
}独立callState事件采用同一active/revision/candidateSessionId/reason并带requestToken=s13-candidate-cancel,事件自身使用新msgToken/eventSeq。candidateCancelled是操作结果,不是整体CallPhase。
S13-M20 · callControl
{
"msgToken": "s13-19",
"method": "callControl",
"sessionId": "s-ai",
"params": {
"operation": "escalate",
"expectedRevision": 0,
"target": {
"kind": "service",
"id": "human-support"
},
"shareContext": false
}
}S13-M21 · callState
{
"msgToken": "s13-19",
"method": "callState",
"sessionId": "s-ai",
"data": {
"state": "transferring",
"revision": 1,
"candidateSessionId": "s13-human",
"localSessionId": "s13-human-local",
"callGroupId": "s13-ai-human-group"
},
"code": 200
}S13-M38 · sessionInvite
{
"msgToken": "s13-s13-human-invite",
"method": "sessionInvite",
"sessionId": "s13-human",
"eventSeq": 1,
"params": {
"purpose": "humanCall",
"transport": "webrtc",
"admission": "accept",
"tracks": [
{
"trackId": "voice",
"kind": "audio",
"sourceId": "microphone",
"sourceType": "microphone",
"direction": "sendrecv",
"codec": "opus",
"state": "requested"
}
],
"expiresAt": 1900000000000,
"callType": "voice",
"callGroupId": "s13-ai-human-group"
}
}S13-M48 · sessionInvite
{
"msgToken": "s13-human-local-invite",
"method": "sessionInvite",
"sessionId": "s13-human-local",
"eventSeq": 1,
"params": {
"purpose": "humanCall",
"transport": "webrtc",
"admission": "accept",
"tracks": [
{
"trackId": "voice",
"kind": "audio",
"sourceId": "microphone",
"sourceType": "microphone",
"direction": "sendrecv",
"codec": "opus",
"state": "requested"
}
],
"expiresAt": 1900000000000,
"callType": "voice",
"callGroupId": "s13-ai-human-group"
}
}S13-M56 · sessionReject
{
"msgToken": "s13-s13-human-invite",
"method": "sessionReject",
"sessionId": "s13-human",
"params": {
"reason": "userRejected"
}
}S13-M57 · requestAck
{
"msgToken": "s13-s13-human-invite",
"method": "requestAck",
"sessionId": "s13-human",
"code": 200,
"data": {
"requestMethod": "sessionReject",
"result": {
"state": "ended",
"reason": "userRejected"
}
}
}S13-M63 · sessionReject
{
"msgToken": "s13-human-local-invite",
"method": "sessionReject",
"sessionId": "s13-human-local",
"params": {
"reason": "userRejected"
}
}S13-M64 · requestAck
{
"msgToken": "s13-human-local-invite",
"method": "requestAck",
"sessionId": "s13-human-local",
"code": 200,
"data": {
"requestMethod": "sessionReject",
"result": {
"state": "ended",
"reason": "userRejected"
}
}
}S13-M61 · callControl
{
"msgToken": "s13-escalate-cancel",
"method": "callControl",
"sessionId": "s-ai",
"params": {
"operation": "cancel",
"expectedRevision": 1,
"candidateSessionId": "s13-human"
}
}S13-M62 · callState
{
"msgToken": "s13-escalate-cancel",
"method": "callState",
"sessionId": "s-ai",
"code": 200,
"data": {
"state": "active",
"revision": 2,
"candidateSessionId": "s13-human",
"localSessionId": "s13-human-local",
"callGroupId": "s13-ai-human-group",
"reason": "candidateCancelled"
}
}S13-M39 · sessionAccept
{
"msgToken": "s13-s13-human-invite",
"method": "sessionAccept",
"sessionId": "s13-human",
"params": {
"acceptedTracks": [
"voice"
]
}
}S13-M40 · requestAck
{
"msgToken": "s13-s13-human-invite",
"method": "requestAck",
"sessionId": "s13-human",
"code": 200,
"data": {
"requestMethod": "sessionAccept",
"result": {
"state": "negotiating"
}
}
}S13-M49 · sessionAccept
{
"msgToken": "s13-human-local-invite",
"method": "sessionAccept",
"sessionId": "s13-human-local",
"params": {
"acceptedTracks": [
"voice"
]
}
}S13-M50 · requestAck
{
"msgToken": "s13-human-local-invite",
"method": "requestAck",
"sessionId": "s13-human-local",
"code": 200,
"data": {
"requestMethod": "sessionAccept",
"result": {
"state": "negotiating"
}
}
}S13-M41 · mediaOffer
{
"msgToken": "s13-s13-human-offer",
"method": "mediaOffer",
"sessionId": "s13-human",
"params": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S13-M42 · mediaAnswer
{
"msgToken": "s13-s13-human-offer",
"method": "mediaAnswer",
"sessionId": "s13-human",
"code": 200,
"data": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
}
}S13-M43 · mediaState
{
"msgToken": "s13-s13-human-connected",
"method": "mediaState",
"sessionId": "s13-human",
"params": {
"mediaRevision": 1,
"state": "connected"
}
}S13-M44 · requestAck
{
"msgToken": "s13-s13-human-connected",
"method": "requestAck",
"sessionId": "s13-human",
"code": 200,
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 1,
"state": "connected"
}
}
}S13-M51 · mediaOffer
{
"msgToken": "s13-human-local-offer",
"method": "mediaOffer",
"sessionId": "s13-human-local",
"params": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S13-M52 · mediaAnswer
{
"msgToken": "s13-human-local-offer",
"method": "mediaAnswer",
"sessionId": "s13-human-local",
"code": 200,
"data": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
}
}S13-M53 · mediaState
{
"msgToken": "s13-human-local-connected",
"method": "mediaState",
"sessionId": "s13-human-local",
"params": {
"mediaRevision": 1,
"state": "connected"
}
}S13-M54 · requestAck
{
"msgToken": "s13-human-local-connected",
"method": "requestAck",
"sessionId": "s13-human-local",
"code": 200,
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 1,
"state": "connected"
}
}
}S13-M65 · focusControl
{
"msgToken": "s13-ai-group-suspend",
"method": "focusControl",
"sessionId": "s-ai",
"eventSeq": 101,
"params": {
"operation": "suspend",
"expectedRevision": 10,
"focusId": "ai-conversation-focus",
"resources": ["microphone", "speaker"],
"priority": "conversation",
"resumePolicy": "explicit"
}
}S13-M66 · focusState
{
"msgToken": "s13-ai-group-suspend",
"method": "focusState",
"sessionId": "s-ai",
"code": 200,
"data": {
"state": "suspended",
"revision": 11,
"focusId": "ai-conversation-focus",
"resources": ["microphone", "speaker"]
}
}S13-M67 · focusControl
{
"msgToken": "s13-human-local-group-acquire",
"method": "focusControl",
"sessionId": "s13-human-local",
"eventSeq": 2,
"params": {
"operation": "acquire",
"expectedRevision": 11,
"focusId": "human-local-focus",
"resources": ["microphone", "speaker"],
"priority": "call",
"resumePolicy": "never",
"expiresAt": 1900000000000
}
}S13-M68 · focusState
{
"msgToken": "s13-human-local-group-acquire",
"method": "focusState",
"sessionId": "s13-human-local",
"code": 200,
"data": {
"state": "acquired",
"revision": 12,
"focusId": "human-local-focus",
"resources": ["microphone", "speaker"]
}
}S13-M45 · sessionEstablished
{
"msgToken": "s13-s13-human-established",
"method": "sessionEstablished",
"sessionId": "s13-human",
"eventSeq": 2,
"data": {
"state": "established",
"mediaRevision": 1
}
}S13-M55 · sessionEstablished
{
"msgToken": "s13-human-local-established",
"method": "sessionEstablished",
"sessionId": "s13-human-local",
"eventSeq": 3,
"data": {
"state": "established",
"mediaRevision": 1
}
}S13-M46 · callState
{
"method": "callState",
"msgToken": "s13-audit-44",
"sessionId": "s-ai",
"eventSeq": 102,
"data": {
"state": "transferred",
"revision": 2,
"candidateSessionId": "s13-human",
"localSessionId": "s13-human-local",
"callGroupId": "s13-ai-human-group",
"requestToken": "s13-19"
}
}S13-M47 · sessionEnded
{
"method": "sessionEnded",
"msgToken": "s13-audit-45",
"sessionId": "s-ai",
"eventSeq": 103,
"data": {
"state": "ended",
"reason": "transferred"
}
}S13-M69 · focusState
{
"msgToken": "s13-human-local-group-acquire",
"method": "focusState",
"sessionId": "s13-human-local",
"code": 503,
"data": {
"state": "denied",
"revision": 11,
"focusId": "human-local-focus",
"resources": ["microphone", "speaker"],
"reason": "driverFailed"
}
}S13-M70 · focusControl
{
"msgToken": "s13-ai-group-restore",
"method": "focusControl",
"sessionId": "s-ai",
"eventSeq": 102,
"params": {
"operation": "restore",
"expectedRevision": 11,
"focusId": "ai-conversation-focus",
"resources": ["microphone", "speaker"],
"priority": "conversation",
"resumePolicy": "explicit",
"expiresAt": 1900000000000
}
}S13-M71 · focusState
{
"msgToken": "s13-ai-group-restore",
"method": "focusState",
"sessionId": "s-ai",
"code": 200,
"data": {
"state": "restored",
"revision": 12,
"focusId": "ai-conversation-focus",
"resources": ["microphone", "speaker"]
}
}S13-M72 · focusState
{
"msgToken": "s13-ai-group-suspend",
"method": "focusState",
"sessionId": "s-ai",
"code": 409,
"data": {
"state": "denied",
"revision": 10,
"focusId": "ai-conversation-focus",
"resources": ["microphone", "speaker"],
"reason": "resourceBusy"
}
}S13-M58 · callState
{
"msgToken": "s13-escalate-failed",
"method": "callState",
"sessionId": "s-ai",
"eventSeq": 101,
"data": {
"state": "failed",
"revision": 2,
"candidateSessionId": "s13-human",
"localSessionId": "s13-human-local",
"callGroupId": "s13-ai-human-group",
"requestToken": "s13-19",
"reason": "transferRejected"
}
}S13-M59 · sessionEnded
{
"msgToken": "s13-human-candidate-ended",
"method": "sessionEnded",
"sessionId": "s13-human",
"eventSeq": 3,
"data": {
"state": "ended",
"reason": "userRejected"
}
}S13-M60 · sessionEnded
{
"msgToken": "s13-human-local-ended",
"method": "sessionEnded",
"sessionId": "s13-human-local",
"eventSeq": 3,
"data": {
"state": "ended",
"reason": "userRejected"
}
}S13-M73 · contextSnapshot
{"msgToken":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","method":"contextSnapshot","sessionId":"s13-human","messageSeq":7,"data":{"deliveryId":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","consentId":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","scope":"completedText","sourceSessionId":"s-ai","serviceId":"support","serviceRevision":"reviewed-r1","snapshotVersion":"immutable-v1","snapshotDigest":"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc","firstTurnIndex":1,"lastTurnIndex":1,"expiresAt":1900000000000,"turns":[{"messageId":"user-1","sequence":1,"turnIndex":1,"role":"user","text":"已完成的问题"},{"messageId":"assistant-1","sequence":2,"turnIndex":1,"role":"assistant","text":"已完成的回答"}]}}此分支仅在本人真实授权、原快照导出、最终同事务消费以及实际人工路由持续有效时进入。示例摘要/截止是占位值;原人工remote腿messageSeq按原持久水位分配,不借旧AI事件序号,不固定7。私有队列只固定关联,不保存正文;每次发出前重新校验原授权/ACL/实际路由。完整assistant保留;wire删减了内部身份,不能从turns重算原私有digest。
S13-M74 · contextSnapshotAck
{"msgToken":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","method":"contextSnapshotAck","sessionId":"s13-human","code":200,"data":{"deliveryId":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","consentId":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","snapshotVersion":"immutable-v1","snapshotDigest":"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc","status":"received"}}人工设备按原会话/连接完整校验并实际留存后回显,服务端核原鉴权Topic及冻结关联。不携带私有正文或水位,不以broker确认制造received。重复原报文可重放原ACK;同键换正文、过期、撤销、held、换连接或会话结束不再接受新留存。缺授权整个M73/M74分支跳过,不用空快照假成功。严格契约和SQL组件通过不等于正式dispatcher/C++端云纵切已通过。
S13-M75 · sessionEnd
{"msgToken":"s13-human-hangup","method":"sessionEnd","sessionId":"s13-human-local","params":{"reason":"hangup"}}只使用当前原人工腿,不发送给s-ai;输入来自已鉴权Topic,正文不自报主体、Owner或连接代次。D3发起时替换为其原人工腿,不能把同token当跨腿授权。
S13-M76 · sessionEnded
{"msgToken":"s13-human-hangup","method":"sessionEnded","sessionId":"s13-human-local","code":200,"data":{"state":"ended","reason":"hangup"}}原请求应答,不携带eventSeq;表示原终态已持久确认,不替代M79。
S13-M77 · sessionEnded
{"msgToken":"s13-human-hangup","method":"sessionEnded","sessionId":"s13-human","eventSeq":5,"data":{"state":"ended","reason":"hangup"}}对端事件不带code;序号取该腿实际水位下一项。示例不是双方共享事件序列。
S13-M78 · focusControl
{"msgToken":"s13-local-human-release","method":"focusControl","sessionId":"s13-human-local","eventSeq":6,"params":{"operation":"release","expectedRevision":13,"focusId":"human-local-focus","resources":["microphone","speaker"],"priority":"call","resumePolicy":"explicit"}}取原本端完整组及当前资源CAS;原请求ACK不占事件序号,不能要求另一条本端Ended事件补序号。设备停止业务腿后仍需沿Global处理此唯一收尾。
S13-M79 · focusState
{"msgToken":"s13-local-human-release","method":"focusState","sessionId":"s13-human-local","code":200,"data":{"state":"released","revision":14,"focusId":"human-local-focus","resources":["microphone","speaker"]}}只有原双端实际false票据完成才发送成功;失败或未知按焦点命令原契约回报,不能照抄成功示例。
S13-M80 · focusControl
{"msgToken":"s13-remote-human-release","method":"focusControl","sessionId":"s13-human","eventSeq":6,"params":{"operation":"release","expectedRevision":1,"focusId":"human-remote-focus","resources":["microphone","speaker"],"priority":"call","resumePolicy":"explicit"}}对端Ended已占示例eventSeq=5,下一项为6;资源修订独立于eventSeq与呼叫修订。本端示例CAS不能复制给对端。
S13-M81 · focusState
{"msgToken":"s13-remote-human-release","method":"focusState","sessionId":"s13-human","code":200,"data":{"state":"released","revision":2,"focusId":"human-remote-focus","resources":["microphone","speaker"]}}对端独立实际释放证明。两端各自关闭本地媒体对象及共享连接的事实还须另外观察,不从平台ACK推断。
S13-M82 · sessionEnded
{"msgToken":"s13-human-hangup","method":"sessionEnded","sessionId":"s13-human-local","code":200,"data":{"state":"ended","reason":"hangup"}}仅原主体与不可变请求的重复M75触发,逐字返回M76;不新增eventSeq、outbox或focus操作。错误token、换连接代次或过期不适用;是否兼容空实例仅沿原非分享冻结契约,不能让客户端自填实例绕过来源校验。
媒体与本地动作
| 编号 | 路径 | 格式与约束 |
|---|---|---|
| S13-R01 | D→P | ICE与DTLS握手,非MQTT;失败走S11 |
| S13-R05 | D2→P | WebRTC ICE/DTLS;独立Peer;15秒超时撤销候选腿 |
| S13-R02 | P→D | 停止本呼叫原声音轨转发;保持信令,不自动发送保留音乐 |
| S13-R06 | D3→P | WebRTC ICE/DTLS;独立Peer;15秒超时撤销候选腿 |
| S13-R07 | D3→P | WebRTC ICE/DTLS;独立Peer;15秒超时撤销候选腿 |
| S13-R08 | D→P | D的新人工腿ICE/DTLS;不借旧AI Peer、密钥或媒体代次;原候选期限更早时服从原期限 |
| S13-R09 | D↔D3(经平台媒体节点) | 两个人际WebRTC音频轨实际传输;仅切换屏障后开启,非MQTT;必须验证实际双向解码而非仅握手 |
异常、状态与资源释放
路由与信封见公共约定;阶段性状态不代表最终完成。操作终态时限见命令手册;编号、超时等元信息不发送。
能力不足422、无权限403、资源/修订号冲突409、超时504按S11处理,不静默开启设备能力。同token只重放原结果;事件按eventSeq去重,旧会话/端代次不可恢复。验证本页正常路径、alt分支及支持范围断言。文档通过不代表代码或硬件已实现。
D2为原被叫,D3为另一个已授权转接或人工端,彼此鉴权Topic和会话腿不得复用。原呼叫主叫同时申请麦克风sendonly和扬声器recvonly,不以只有上行的轨宣称双向通话。候选失败时撤销其邀请/Peer/令牌,原呼叫与资源占用继续;转人工分支是另一独立AI会话的示例。
AI转人工的失败与切换边界(扩展契约,须确认支持)
下表描述尚未实际suspend的失败。进入第三屏障后发生同类撤权、超时或取消,须按后面的分阶段补偿核对真实资源与路由提交结果,不能直接套用“原AI实际继续”。
| 触发 | 原AI作用域结果 | 新人际两腿清理 | 原AI及共享驱动 |
|---|---|---|---|
| D3或D拒接;忙线为sessionReject.reason=resourceBusy | M58 reason=transferRejected | M59/M60 reason=userRejected | 原仍授权AI继续,不把拒接当AI终态 |
| 首次候选45秒或更早邀请截止到期 | M58 reason=transferTimeout | M59/M60 reason=inviteTimeout | 不续期;旧超时不作用于新候选 |
| 任一Peer协商/连通失败 | M58 reason=transferMediaFailed | M59/M60 reason=mediaFailed | 不切麦克风/播放,释放候选Peer |
| 目标明确撤权 | M58 reason=transferPermissionRevoked | M59/M60 reason=permissionRevoked | 不向目标共享正文;原AI仍授权才继续 |
| 原主体权限读取未知或目标不可用 | M58 reason=transferUnavailable | M59/M60 reason=mediaFailed | 未知不猜撤权或完成,不安装候选 |
| D在提交前撤原候选 | M61/M62 state=active、reason=candidateCancelled | M59/M60 reason=callerCancelled | 不发原AI sessionEnded;原token只重放 |
| 原AI用户结束或自身明确撤权 | 原AI沿原sessionEnd/终态路径 | 结束其尚未提交候选 | 不用“失败保AI”绕过原权限或用户终止 |
M56–64示例分别展示拒接与取消的互斥路径;M59/M60的示例reason=userRejected只对应尚未suspend的拒接,其他提交前失败按表替换,并按各腿实际eventSeq推进。M58的failed是本次escalate操作失败,不把s-ai改成失败终态;但原AI会话保留不等于实际采集/播放已恢复。尚未分配双腿的422不带localSessionId/callGroupId,沿原token返回不支持原因,不凭service字面量选择管理员。
本次实现收敛:撤候选的双腿结束复用人际通话已有callerCancelled,不使用表中原设计的userHangup,因为撤销尚未提交候选不是挂断原AI。拒接ACK的result.state=ended并保留原请求的userRejected/resourceBusy/privacyEnabled;异步候选终态规范为userRejected。这些限定仅针对本次新人际voice候选,不能据此改变现行视频或其他用途的应答格式。
第三屏障与分阶段补偿(扩展契约,须确认支持)
| 阶段及证据 | 平台与设备处理 | 不能声称的结果 |
|---|---|---|
| 尚未实际suspend;M72仅在原驱动保证未执行时回denied | 清候选,原仍授权AI及实际归属保持;M65回执缺失不属于明确未执行 | 不把未知suspend当保持原物理归属 |
| M66已确认suspended;M69明确未acquire且路由明确未提交 | 复核原AI权限、用户意图、原租约/完整组、截止和当前CAS,再发M70;只在M71实际restored后显示AI输入/播放恢复 | 不凭原模型仍在线、候选已关闭或restore受理宣称active |
| acquire或路由提交未知,包括原回执/提交回复丢失 | 保留原token、字节、代次与绝对截止,进行有界原操作查询或重放;设备保留实际单一归属/围栏,过期按原许可停止,不能续期或新建恢复意图 | 不盲目restore导致双采集,不发transferred;不因没收到ACK推断未执行 |
| M68原整组实际acquired且当前授权/候选代次/原连接/期限/CAS仍有效 | 平台持久确认原回执与人际路由提交;之后M45/M55,再M46/M47 | M68本身不等于提交;Broker接纳、单轨active和mediaState.connected均非第三屏障 |
| 路由已提交后,本地驱动/人际媒体又失败 | 按已提交新人际通话失败与资源归属收尾;迟到候选取消不能倒退提交阶段 | 不回滚已经变化的路由、不以旧AI恢复伪装本次未切换、不冒报仍正常通话 |
M65–72不添加新method或焦点operation。M65/M66固定原AIs-ai/ai-conversation-focus,M67/M68固定原本端新人际腿s13-human-local/human-local-focus;关联来自原escalate账本,不按全局当前会话推测。每次操作只在完整实际组完成后推进设备全局revision;M69/M72拒绝不推进,原token重放原结果不再次切换。示例M70的expiresAt须是原AI仍有效许可、原租约与该次授权截止的最早值;M67须服从原候选/会话/授权截止,不因共享同一示例数字续期。若存在其他合法资源变化,先核实际新CAS,不能照抄11。
此处在途截止和已接通业务截止必须分离。内部HumanBusinessDeadline从原AI已配置且已授权的会话业务Deadline固定(双方IM授权若有更早截止取最早),并写入新人际双腿业务Deadline;45秒候选与30秒邀请只限制准备,双Peer实际就绪后首次固定的FocusDeadline最多15秒且不得越过原45秒或业务截止。M67的租约expiresAt取原持久人工业务截止,不取邀请期限;其请求/实际ACK和三屏障提交仍须在原焦点操作预算内完成。提交仅改变阶段,不刷新任何截止。旧意图缺这些来源保持未知/拒绝最终切换,不从ended、请求期限或Redis忙线续租补授权。当前期限分离已接入准备事务,最终人际组路由及持续Owner生命周期尚待接线和真实端云验收;完成后原AI模型/UDP结束只释放旧AI上下文,不能调用通用Owner关闭撤掉人工组,人工自身断连、撤权、租约失效或业务截止才按实际资源终态收尾。
仅对原授权escalate账本绑定的prepared候选,在建立前严格特批M67及其M68/M69回执;目标腿、原AI、呼叫组、原连接、能力、候选/媒体代次和期限都须固定验证,普通negotiating会话仍不得操作焦点。后端已实现原内部出处的有限特批、原Queue/完整ACK及生成RPC边界回归;实际共享宿主与最终平台提交尚未闭环,不能用组件回归倒推端云已支持。
人工取得屏障包含两端,不仅本端D。双Peer prepared之后,平台先向D3的原remote腿按M67合同发送独立完整组focusControl.acquire;D3按M68合同回原token实际acquired后,才对D发M65/M66,随后D的M67/M68。D3必须是明确pureHuman接收端并具有自己的首次完整idle出处;D3已有AI租约、资源未知或在途控制均拒绝,不能隐式取消目标AI。两端各有独立连接/Owner栅栏、focusId、资源CAS及实际ACK,expiresAt均取原持久HumanBusinessDeadline,不越过原阶段期限取得。最终三CAS需核两个当前完整组实际租约;prepared、CheckVoice、Broker接纳和一端ACK都不足以切换。本段没有新增报文method、escalate ACK字段或设备自报权限,双端真实移交仍待验。
共享采集对象在候选等待期始终由原AI持有。M66之后旧AI转发停止,M68只在同一物理对象已实际归属新人际采集/播放后成立;候选媒体仍由平台屏障禁转,直至原持久提交明确成功。M43/M53只证明网络连通;M45/M55是完成第三屏障与路由提交后的确认,不再触发尚未证实的移交。D须把它们同原关联及已完成焦点事实核对,才能呈现M46或释放M47的旧AI资源;跨会话事件不可按最新session猜测。旧AI释放不得顺带关新人际驱动,晚到旧AI音频/文本/工具结果必须围栏。全过程扩展契约,须确认支持,不以一次mediaState或“transferred”文本认定切换。
后端旧AI完整组正式释放已接原Owner持续入口:四条最终通知的原ID/SHA都已交Broker后才排唯一focusControl.release,实际设备仍需核原AI终态及原资源;不把Broker接纳称设备完成。原生成入口的完整成功ACK写独立原释放墓碑,连接全局CAS前进而新人际租约与Peer不变。后继Human保持/恢复仍以原callControl token跨两腿各自focusControl关联,不能混用呼叫修订与资源修订;双完整组实际ACK之后才发held/active。原十秒释放截止、SQL未知读回和原实例替换均有受控回归,私有上下文原合法读取/留存ACK不因精确旧AI释放失效;这不是实际两共享宿主/模型/Broker端云通过记录。
合法保持/恢复须先确认原旧AI正式释放完成;四通知仍pending、释放排队或未知都不能先停人工RTP或占用双方焦点。原typed409拒绝不改媒体,业务期限及Owner到期仍精确关闭人工组,不以等待释放延长授权。
第一实现阶段可保持不分享上下文,但授权分享仍是后继必须实现项:需要真实Consent引用校验、撤销及限定范围交付。拒接、忙线、撤销、超时不需要分享同意,不能为候选清理要求额外consent。
后继实施验收断点
- 正式AI Owner受理escalate,原token幂等、修订冲突、授权目标与两腿关联;当前拒绝入口不能假装支持。
- 两个邀请乱序抵达、错组/错腿/错原token、关联超时有界丢弃;普通来电不自动抢占AI。
- 仅D3 accept或仅一腿网络就绪时,原AI实际输入/回复持续;同时验证只有一条物理采集路径。
- 无原完整租约、仅speaker能力、缺实际microphone驱动、普通negotiating腿及错候选关联均拒绝;不凭priority提权或开启第二套采集。
- M65–72完整资源/token/CAS关联、单资源假成功/迟到代次拒绝;实际suspend后明确未acquire才允许受授权restore,实际restored前不报active。
- 原回执丢失、路由提交回复丢失、恢复拒绝及授权/期限变化均保守未知;不盲恢复、双采集或续期,不回滚已提交路由。
- 两腿真实双向非静音解码、整组实际acquired后的再次授权/代次复核与持久提交,以及旧AI关闭不影响人工媒体。
- 拒接、忙线、45秒到期、撤候选、目标撤权、未知读失败保留仍授权AI;原AI结束并发候选就绪不得复活。
- 成功/失败终态后迟到的旧AI内容、旧候选事件与旧定时器不能污染新腿;原token重放不重复邀请/切换/续期。
上述为待实现测试用例,不是新增真实通过记录;人际第16轮保持/恢复事实及原历史产物不因本次文档hash变化重写。
验证入口
更新日志
2026/10/16 16:04
查看所有更新日志
fe3a7-docs(AI与音视频): 按场景整理完整接入流程与命令契约于
