21 KiB
Go SIP Agent:配置读取与有界外呼迭代计划 v0.1
当前迭代唯一执行入口。状态:项目提案;新 HTTP/MQ 合同、实现及验收均未完成。 现行 contracts/upstream/v1/ 和代码仍是旧基线,不将本文当作上线授权。分项设计:有界消费与控制通道;对外结构:第三方对接;配置字段:字段提案、草案 Schema。分项材料须与本文一起更新,不能继续使用旧 ETag/304、控制 CAS 或即时反馈目标。
1. 范围和完成标准
当前 P1 仍为单 D、单 Agent、单 Asterisk、单 Cell、单租户,允许同租户多任务验收;第二租户/多 D 只可另做明确标注的合同 fixture,不等于业务运行授权。真实 SaaS、OSS、云、供应商消费和外呼均另获授权;真实外呼仍遵守白名单、Asia/Shanghai [09:00,20:00) 及每线路/号码每日次数限制。未经新合同和验收,不替换现行运行规则。
拟定四条只读 GET,共用 X-DISPATCHER-id 和 X-DISPATCHER-SECRET-KEY,无请求体:
| 路径 | 用途与状态 |
|---|---|
/internal/v1/dispatcher/sip |
用户指定路径;本 D 获管理面批准的 SIP 全量。 |
/internal/v1/dispatcher/task/:task_id |
用户指定路径;任务归属、路由/主叫、智能体、时段及两项任务级超时。 |
/internal/v1/dispatcher/tasks(可 ?after=<cursor>) |
用户指定路径;启动一致全量快照,运行中每 30 秒按变更游标发现任务。 |
/internal/v1/dispatcher/tenant/:tenant_id/quota |
新增路径/字段为项目草案:取得任务后按其 tenant_id 读取该租户分配给本 D 的并发额度;实际路径须 SaaS 签收。 |
任务队列及精确绑定只由 SaaS 创建、维护和退役;D 只消费,不建队、不绑定、不删除。 SaaS 先确认持久队列 ready 再发布 persistent 消息,mandatory 无 return 且 confirm 成功才记入队。D 离线时消息可积压;无队列时未成功入队的原消息由 SaaS 保留,就绪后按原身份重新发布,不能靠 D 重启倒灌。任务队列按 D+任务 ID 定位;租户身份保留原值用于核验和额度汇总。
用户明确的消费规则:pause 保留积压,resume 消费原队列积压;stop 持久生效后静默消费并 ACK 所有未接纳积压,不拨号,不向 SaaS 发布这些消息的回执或通话结果。 静默只限定已停止任务的未接纳命令:停止控制本身仍有处理回执;已接纳/在途通话按 drain/hangup 处理并保留其最终结果。D 的错误日志、停止状态和计数不静默,ACK 丢失后重投仍不拨号、不补发被抑制结果。
完成分三层:C:F01/F07 正式来源、版本、严格 Schema、正反例与验收约定签收;L:单 D 本地隔离闭环和故障矩阵通过;M:多 D 独占资源/份额为另行授权的后续。项目字段草案、本地 Mock 和旧测试不能代签 C 或真实供应商结果。
2. 权威资料和读法
先读本文并按 §4 选择 F 包,再读架构、现行验收、通信合同、开源复用及 contracts/upstream/v1/。新旧冲突须版本化替换,不向现行严格合同偷偷加字段。页面分析只作页面语义来源,不证明现网字段。原 plan-0918不回写;本计划 §8 是唯一新台账。
3. 冻结目标与处理规则
3.1 配置、路由、时限
- management 是 SIP 唯一编辑/审批面,SaaS 只分发获批完整版本。SIP 变更先关准入、排空/对账,再核验实际加载;发现变化约 60 秒不等于加载完成约 60 秒。供应商 transport/auth/registration 不明不得给 real 猜默认值。
- 新
call.execute.payload仅task_id/callee;外呼信封仍有command_id防重复拨号。任务必须返回tenant_id/tenant_key,D 核对消息与任务归属后再按tenant_id取额度,身份错配/缺失即拒新准入。任务配置不返回agent.content_sha256;版本不可变,同版本异内容拒绝,已有执行持久快照不漂移。 - 最小路由约定(项目草案,F01 签收):
allowed_trunk_ids按列表顺序作为候选优先级,选首条满足时段、已加载状态、供应商/线路额度且支持任务caller_profile_id的线路;无满足项不接纳。caller_profile_id是新增任务级明确引用,必须命中选中线路的获批主叫,不默认取第一个主叫。route_policy_id只标识这份任务路由,不依赖另一个未定义的查询接口。选定线路/主叫后持久绑定;拨号失败或未知不自动换线重拨。 ring_timeout_ms是任务级振铃上限;通话有效上限是任务max_call_duration_ms与已授权 AIconversation.max_duration_ms的较小值,控制器和执行侧均使用同一值。两值不相同必须记录来源/有效值,不改写智能体原快照或悄悄放宽任何上限。没有逐呼variables的新合同不提供联系人变量来源;需要未提供变量的提示词不得以空字符串代替继续执行,须在 F01 明确静态提示词范围或补齐获批来源。- SIP/任务配置约 60 秒缓存到期重取完整
200,不使用 ETag/304;过期/失败拒绝新准入,不影响既有执行快照。配置内status=running不是恢复许可,状态按 §3.3 独立处理。
3.2 租户额度
取得有效任务的 tenant_id 后,D 请求拟定 /internal/v1/dispatcher/tenant/:tenant_id/quota。响应包括 D、tenant_id、原值 tenant_key、额度版本、max_concurrent_calls(允许 0)、有效截止时间;该值是 SaaS 分配给此 D 的租户份额,不是每个任务各得一份。相同租户各任务复用同一额度快照/占用账本,SaaS 必须保证 tenant_id 与 tenant_key 一对一。
额度成功核验后最多缓存约 60 秒且不超过响应有效截止时间;缺失、身份错配、过期或刷新失败,关闭该租户所有任务的新准入,不使用无限额/默认额,不阻塞 stop 静默排空。额度调低时不强挂已接通通话、不抹掉已占用/未知执行,直到占用降至上限以下才再接新呼叫。D 以 SQLite 单事务检查并预留租户+任务+Cell/线路/AI 等额度,不能先分别判断后并发超卖。确认通话终结并释放执行资源后释放通话额度,不等待录音上传或 MQ 最终结果确认;未知通话继续占额。多 D 时各份额之和≤租户总额,未经 F05 授权不开放多 D 运行。
3.3 暂停、恢复、停止与状态来源
SaaS 先持久修改权威任务状态,再向独立 D 控制队列发布 task.control。请求不含 command_id/expected_task_revision,本阶段不设计控制去重;D 按任务串行处理控制与接纳,并持久记录生效状态后才 ACK/回执。
- **pause:**立即关闭新接纳并保存暂停屏障,停止从该任务队列继续取新执行;已投递但未接纳的有界消息退回原队列,不能 ACK 丢弃或搬进无界 SQLite 待拨队列。已有执行按 drain/hangup 处理。重启仍暂停。
- **resume:**重新 GET 单任务配置(不使用约 60 秒旧缓存),只有 SaaS 最新状态为 running、归属/授权/租户额度/时段有效、且本地未 stopped,才解除暂停并恢复消费原积压。无需 SaaS 重新发原消息;已过
not_after的旧消息仍不可拨,暂停不能冻结或延长有效期。过期/窗口外非 stopped 命令给明确拒绝回执,不等待次日自动拨号。 - **stop:**持久化不可逆停止屏障,同任务 ID 不能 resume/重新启用;SaaS 停止新发布。D 不申请通话额度,继续小批量消费未接纳积压,仅计本地处置计数并 ACK,不建外呼结果/outbox,不拨号。已停止任务重投/重启、额度为 0、配置缓存失效时仍可排空;不得借此清掉别的任务、伪造已接纳执行终态或漏掉控制回执/既有通话结果。
- **优先级:**本地 stopped 永久高于任何 running;本地 paused 只能由有效 resume 解除。
tasks增量/全量及缓存更新可使状态更严格,不能清除已持久的暂停/停止屏障,且低于已知task_revision的状态不得覆盖新状态。冷启动恢复本地屏障与 SaaS 全量后取更严格者;冲突/缺失关闭新准入,不丢已有执行事实。 - **无编号乱序:**控制重投可能重复返回回执,不保证按消息身份“只处理一次”。pause/stop 先关闭准入;与 SaaS 最新状态不符、不可核验或接收乱序时保持关闭并返回明确失败,不根据到达先后自动恢复。恢复必须重新发送有效 resume 并核对最新权威状态;不引入替代 command_id 或控制 CAS。SaaS 不可把发布成功视为控制已应用,丢失回执下状态不明不得主动扩量。
3.4 任务发现、发布与期限
D 启动/重启用 /internal/v1/dispatcher/tasks 拉一致全量快照和水位,运行中每 30 秒 ?after=<cursor> 拉本 D 新增/更新/撤销。cursor 是变更水位,不是最大 task_id;完整分页连贯、持久应用成功才推进。游标失效、缺页、快照不一致时关闭受影响任务新准入并重拉全量。发现清单/任务响应必须提供 tenant_id/tenant_key 以便取额度。无变化不撤销消费关系。
队列 ready 不等于 D 已开始消费。 首条任务可能等待轮询、分页、配置/额度读取和可用名额;30 秒是轮询间隔,不是端到端发现 SLA。SaaS 设置的 not_after 应覆盖允许的排队和准备时间,不能用固定 30 秒示例承诺离线恢复必拨。D 重启仅恢复原消息:未过期且有效的才接纳;过期明确拒绝(已 stopped 则静默 ACK),绝不顺延期限/自动造新 command_id 重拨。若要求更短首呼时限,必须在 F07 另定就绪通知协议,不能假设已存在。
SaaS 清单须保留已 stopped 但未排空任务;停止新发布、积压/未 ACK 排空、无未知执行并完成双方约定的退役核验后,才撤销任务归属/删除队列。该核验不靠逐条停止回执,队列空不代表无在途通话;撤销握手待 F07 冻结。D 不创建/删除队列;任务 ID 唯一性、key 长度/字符、队列总数上限一并冻结。
3.5 最终结果与无录音
保留呼叫/控制回执及一种最终 call.result,不保留对外 query/replay、实时文字/拒联/录音拆分事件。用户已选择仅最终反馈;取消即时拒联的产品风险与现有验收冲突须正式业务签收。最终结果的身份在本地持久化,MQ 重投仍是同一份事实,不重新拨号或上传。
- 已产生录音:上传 OSS 成功后
recording.status=uploaded、携带路径;上传永久失败/到有限期限后unavailable、明确错误与 null 路径。具体期限是 F07 阻塞项,不无限等待。 - 通话已尝试但忙线/无应答等未产生录音:终结已确认后即可发唯一结果,
recording.status=not_created、身份/路径等资产值为 null,原因如no_answer;不申请上传、不假称上传失败。录音本应生成却失败用unavailable和明确阶段原因,不伪装正常无录音。 - 未接纳且被停止屏障吞掉:无命令回执、无最终结果;其他未接纳拒绝只有命令回执,不能伪造通话。已接纳取消/失败/挂断仍按其事实形成最终结果。
outcome反映通话本身,录音错误写 recording 不改成呼叫失败。通话额度释放与上传/通知独立;日志只保留脱敏事实,不输出完整音频/文本/密钥。- 最终文字合并后的消息大小与现行 MQ 上限可能冲突,F07 必须冻结可容纳的正文上限和明确失败策略,不截断完整转写、不拆成用户已移除的实时事件来掩盖。
4. 依赖顺序与工作包
执行顺序:F00 → F01(HTTP/配置/额度)与 F07(MQ/发现/控制/结果)并行冻结 → 联合一致性签收 C → F02 → F03 → F04 → F08 → F09 → F06。F05 是另获授权的后续。 F01 不再要求先完成 F07 的 MQ 改写;二者共同签收后才能进入新路径实现。F03 单独负责新队列消费/状态屏障,F08 只集成结果交付和受控切换,不重复开发同一消费路径。
| 工作包 | 输入、责任与交付 | 门禁 |
|---|---|---|
| F00 草案整理 | 集成负责人同步本文、分项设计、对接文档、配置 Schema/示例;标明用户给定路径与项目新增额度/路由字段。 | 正反例可验证,不冒充 SaaS 现网。 |
| F01 HTTP 与配置/额度合同 | SaaS/management 签收四条 GET、两 Header、身份映射、任务主叫/候选优先级、两时限较小值、授权/缓存/配置不可变及租户额度份额/版本/有效期。 | 严格 Schema、来源/版本/哈希、正反例;静态提示词或变量来源明确。外部未签收则 blocked。 |
| F07 MQ、发现及控制/结果合同 | 与 F01 并行:SaaS 签收任务发现分页/水位、先建后发、队列生命周期、精简 call.execute、无编号控制、pause保留/resume续消费/stop静默排空、状态优先级、回执/最终结果及无录音;联合核验 HTTP 与 MQ 相同身份/版本。 | 新版本权威包及业务签收 C;撤销旧 query/replay/配置MQ/拆分事件;未决结果期限/消息大小/退役握手全部冻结。 |
| F02 配置与额度读取(C 后) | SaaS 提供四接口;D 读取并校验 SIP 实际加载、任务租户映射、按 tenant_id 的额度,完整 200 缓存;有期限拒绝与持久快照。 | 断 SaaS、降额、同租户多任务、过期/错身份、新旧配置竞态不超额/不漂移。 |
| F03 消费/发现/控制(F02 后) | D 移除新协议 --tenant-key 自建租户队列路径,按 SaaS 已建任务队列消费;发现游标/暂停恢复/停止静默ACK/独立控制与原子额度;未接纳仍留 MQ。 |
§5 的队列/控制矩阵通过;D 无建队权限仍可工作,stop静默但可排查。 |
| F04 时段及最后拨号屏障(F03 后) | 任务×线路时段、排除日期、白名单、有效期和已绑定时限在 D/执行侧一致,最后许可与控制串行判定。 | 窗口边界/跨日/更新/暂停竞态无错误拨号,旧固定窗只在合同/验收批准后替换。 |
| F08 结果与受控切换(F04 后) | 组装 uploaded/unavailable/not_created 的最终结果与既有命令/控制回执;通话释放独立于上传;旧新版本互斥,恢复原身份 outbox。 | 本地全流程无重复拨号/PUT,停止积压不产生回传,已有执行结果不丢失。 |
| F09 本地验收(F08 后) | 集成负责人运行 §5 全矩阵;单 D 单租户多任务为 L,扩展 fixture 标为非 P1。 | gofmt、go vet ./...、go test -race ./...、go build ./...、本模块覆盖率≥65%,脱敏证据。 |
| F06 发布/切换(F09 后) | 单写 §8 状态,核对合同/制品/队列实际版本;真实 SaaS/OSS/云/线路另外授权。 | 旧本地证据不代签;回退不能并行旧新写入/额度或引起重拨。 |
| F05 多 D(后续另授权) | SaaS 固定任务归属、分配各 D 有界租户/供应商份额;D 独占 Agent/Asterisk/持久目录。 | 各份额总和≤总额,未知执行不跨 D 迁移,不用 fixture 冒称双 D 业务。 |
5. 必测输入与预期结果
| 用例 | 输入/故障 | 必须观察到的结果 |
|---|---|---|
| 配置结构 | 缺身份 Header、task/消息/额度 tenant_id 或 tenant_key 不一致;agent.content_sha256/旧逐呼字段回流 | 拒绝新准入,不能猜默认/覆盖;call.execute.payload 仅 task_id/callee,task含两超时与明确主叫。 |
| 配置/路由 | 第一候选不可用、第二可用;无主叫映射;任务120秒/AI90秒;提示词缺变量 | 首个满足条件的候选并固定;主叫不可解/变量缺失不拨;有效时限90秒,两个控制点一致,拨后失败不自动换线。 |
| 租户共享额度 | 同 tenant 两任务额度各10、租户上限3,同时请求4次 | 合计最多3个占用;不同任务不各得3。未知占用计入。 |
| 降额/失效 | 已占3时从3降为1;额度0、有效期到、HTTP故障 | 现有不强挂、不清未知;新准入关闭,占用低于新上限且授权有效才接新;控制/stop排空不被额度阻塞。 |
| pause/resume | 暂停时队列100条、D已有有界未接纳交付;重启后恢复 | 暂停不丢消息/不新拨;未接纳退回原队列;重启仍暂停;有效resume继续消费原100条且无需SaaS重投,已过期的明确拒绝。 |
| stop 静默 | 未接纳积压100条、在途2通、stop;ACK丢失/重启/额度0 | 100条最终ACK,originate=0、新回执/最终结果outbox=0;本地计数可核查。stop控制有回执,2通按策略终结并各有最终结果;其他任务不受影响。 |
| 状态优先级 | pause/stop后收到旧running快照或低版本tasks;旧resume迟到/控制重复/HTTP断连 | 不自动恢复;resume未获最新running/未过屏障即明确失败;stopped不可逆。控制不按消息身份去重,不保证只回一次;回执不明不当成功。 |
| 新任务/离线期限 | 刚过轮询点新建队列;离线超过not_after;首条期限不足准备时间 | 消息先入已建队列;恢复只消费仍有效者,过期不拨不顺延,不自动新建外呼命令;30秒只是发请求周期。 |
| 发现/退役 | 较小ID任务变更、分页缺页/重复、游标失效、SaaS创建前误发、stopped仍有积压 | 不漏旧任务变更;重拉一致全量不越过未应用页;未入队原消息由SaaS保留;stopped保留清单直到静默排空,无未ACK/未知执行再退役。 |
| 队列权限/配额 | D禁止create/bind/delete、队列满、SQLite满盘、租户满额 | D只消费,不补建;SaaS保留未成功发布消息;事务失败不ACK已接纳;不会搬全部积压进SQLite,不阻塞控制/stop清理。 |
| 无录音/失败 | 无应答/忙线且无录音;应有录音却失败;OSS超时;停止未接纳命令 | 正常无录音not_created且不等待上传;故障unavailable有阶段原因并在签收期限内最终收口;停止未接纳无回传;不能伪造call_id/成功路径。 |
| 释放与结果 | 已确认结束但上传慢、MQ confirm丢失或重启、完整转写超过预算 | 通话额度已释放、未知仍占额;原结果身份重投不重拨/PUT;按签收的大小/失败合同处理,不静默截断或假成功。 |
| 时间及真实边界 | 任务/线路交集、空日、排除日、左闭右开、最后许可前控制到达 | 不跨窗或被暂停/停止后新拨,不等待次日自动执行;Mock时钟不等于real放行。 |
6. 写入与实施边界
项目设计在自身 docs;现行 Schema 保持不动,新合同先签收再导入唯一版本化来源,不手工维护两套发布 Schema。本文/分项/guide/字段提案必须同步;源码、截图、真实凭据、无关父仓库不改动。TDD 先失败后实施,复用现有库,禁止隐藏错误、HTTP/MQ配置回退、重复外呼。大改另开分支,未获得子 Agent 授权由当前负责人执行。
7. I/M/G 前置
I:用户方向确认不等于 SaaS/management 权威签收。四接口、租户份额、路由/控制优先级、新消息 Schema、结果失败期限及退役握手未完成联合 C 前不实现新生产路径。M:旧 W 的通过不能代替新 F02–F09;仅本地隔离验证不代表真线路/OSS通过。G:部署版本、网络/ECS只读核验、SHA-256、systemd enabled+active、Asterisk/ARI/PJSIP、媒体监听和非生产诊断门禁全部保留;实际云/生产/拨号另获授权。
8. 当前事实总台账
| 项目 | 当前事实 | 下一门禁 |
|---|---|---|
| 历史计划 | plan-0918保留原文,只作历史。 | 不回写旧W台账。 |
| F00 | 用户确认按tenant_id另取租户额度、pause保留/resume续消费、stop静默排空;相关文档/项目 Schema 已修订,非现网合同。 | 正反例与文档一致性检查、外部签收。 |
| F01/F07 | 三条原路径/Header用户已指定;新增租户额度路径/字段、主叫/候选规则、控制优先级和无录音结构为本轮项目提案。 | 两合同包并行冻结后联合 C,不互设循环依赖。 |
| F02–F04/F08 | 新路径未实现;现行代码仍是旧 MQ-only/静态租户队列等基线。 | C 通过,逐包 TDD/故障注入。 |
| F09/F06 | 新验收及切换未执行,旧测试不代签。 | L证据与授权,真实联调另行安排。 |
| F05 | 多D/第二租户不在本轮运行范围。 | 另获阶段与额度/资源授权。 |
9. 协作与版本记录
仅集成负责人更新本文 §8、公共合同和合并状态;有并行授权时一 lane 一工作区/独占写集合、每批回归,不假定未跟踪文件在 HEAD。v0.1 是项目规划及字段草案,不是 W01/SaaS 正式发布版本。真实环境的资源、拨号和生产权限不因文档改动增加。