Files
go-sip/docs/contracts/config-read-fields-v0.2-proposal.md
T

101 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 只读配置与租户额度接口:任务、智能体、SIP 字段与返回结构 v0.1(项目内 F01 规范)
**状态:项目内 F01 字段规范;不是 SaaS 已有接口/实际 JSON,也不是外部发布契约。** 本地字段由本文件与[第三方对接契约](../thirds/第三方对接事件与请求消费顺序_v0.1.md)定义,使用严格 Schema、正反例、来源/hash 和 Mock 验证;不等待 SaaS/management 外部签收即可完成本地 C。截图可见的业务含义映射为**项目定义的字段名**;截图没有但需求明确的结构由本项目设计。即使字段名与现有项目 Schema 或历史 OpenAPI 相同,也**不能**据此声称它是当前 SaaS 页面原有后端键。真实配置发布、拨号或外部切换仍需另行授权和验证。
## 1. 来源、交付边界
- **P = 页面观察:**[SaaS 截图分析](../references/saas-page-snapshot-analysis.md) §2–4;只证明表单/列表可见,尤其§7的 **MQ 配置建议是已被新 HTTP 方向取代的历史方案**,不作为新合同。
- **C = 现行外部项目合同:**[AI 配置](../../contracts/upstream/v1/ai-config.schema.json)、[静态 Cell/SIP 制品](../../contracts/upstream/v1/static-cell-artifact.schema.json)及[当前 MQ 消息](../../contracts/upstream/v1/mq.schema.json)。字段语义可复用,但**不是 SaaS 当前 HTTP 响应证据**。任务发现与分页语义以[当前 v0.4 契约](../thirds/v0.4.md)为准;其它历史背景见[第三方对接契约 v0.1](../thirds/第三方对接事件与请求消费顺序_v0.1.md)。旧 [OpenAPI/MQ 只读索引](../references/OpenAPI与MQ字段索引_v0.1.md) 也仅为历史参考。
- **N = 新项目字段:**任务每周多时段/排除日期、SIP 线路时段、任务与单 D 绑定、缓存/版本/错误返回等,由本提案定义;实际 SaaS 接口不存在已验证响应。
路径来源:`/internal/v1/dispatcher/sip`、`/internal/v1/dispatcher/task/:task_id`、`/internal/v1/dispatcher/tasks`(含 `?after=<cursor>`)为用户给定路径;`/internal/v1/dispatcher/tenant/:tenant_id/quota` 与任务路由字段 `route_policy_id`、`caller_profile_id`、`allowed_trunk_ids` 为本地项目定义。它们不是截图/现网接口已验证的响应键;本地 Mock 按本契约验证。
交付物:[新版机器可读响应 Schema](config-read-v0.2.schema.json)、[新版 mock SIP 成功示例](examples/config-read-sip-v0.2.json)([旧 Schema](config-read-v0.1.schema.json)/[旧示例](examples/config-read-sip-v0.1.json)保持历史不变)、[mock 任务成功示例](examples/config-read-task-v0.1.json)、[mock 租户额度示例](examples/config-read-tenant-quota-v0.1.json)、[mock 错误响应示例](examples/config-read-error-v0.1.json)及[预期被 Schema 拒绝的非法示例](examples/config-read-invalid-extra-property-v0.1.json)。四条只读 GET 为本地目标:`/internal/v1/dispatcher/sip`、`/internal/v1/dispatcher/task/:task_id`、`/internal/v1/dispatcher/tasks?after=<cursor>` 与 `/internal/v1/dispatcher/tenant/:tenant_id/quota`。均携带 `X-DISPATCHER-id`(D UUID)及 `X-DISPATCHER-SECRET-KEY`(受控密钥),无请求体;真实 SaaS 实现和字段兼容性未验证。呼叫/控制/回执/最终结果走 MQ,目标移除对外 query/replay,不留旧 AI/SIP 配置 MQ 回退。错误状态和 code 按本文件 §2 与第三方对接契约定义并由 Mock 验证;本地 Schema 不冒充外部权威发布物。
## 2. 请求与共同响应
Dispatcher 仅用 `X-DISPATCHER-id`(全局唯一 UUID)和部署受控的 `X-DISPATCHER-SECRET-KEY` 请求归属资源;不记录密钥或在日志中打印配置提示词。接口只读、无控制副作用;服务端必须核验任务归属。Header 的本地错误约定为 HTTP 401 `unauthorized`、403 `dispatcher_not_authorized`;请求格式错误为 400 `invalid_request`,资源缺失/未归属为 404 `resource_not_found`,租户额度不可用为 503 `tenant_quota_unavailable`,临时服务故障为 503 `service_unavailable`。`GET /internal/v1/dispatcher/tasks` 的启动快照与运行期增量按[当前 v0.4 契约](../thirds/v0.4.md)执行:分页快照不可继续时返回 409 `snapshot_unavailable`,请求无效时返回 400 `invalid_request`/`invalid_page_token`;不沿用历史版 410 `cursor_expired`/`snapshot_expired`。任务发现严格结构见[任务发现 v0.4 Schema](task-discovery-v0.4-proposal.schema.json),不混入本文件的配置响应 Schema。以上仅为本地 Mock/Go 契约,不代表外部 SaaS 状态码。
| 请求 | `200` 返回类型 | 何时读取 | 错误处理 |
| --- | --- | --- | --- |
| `GET /internal/v1/dispatcher/sip` | `resource=sip_config`,本 D 的已批准完整 SIP 快照 | 新 D/重启先取齐并核对 Agent/Asterisk 精确加载;运行中约每 60 秒读取完整配置 | 读取失败/到期停止新执行准入,旧活动通话依原快照排空 |
| `GET /internal/v1/dispatcher/task/:task_id` | `resource=task_config`,归属 D 的单任务配置和已授权智能体快照 | 有待接纳呼叫时获取,活跃任务缓存约 60 秒;resume 必须重取最新配置,不能靠旧 running 恢复 | 失败/过期不放行;已接纳执行仍用原快照 |
| `GET /internal/v1/dispatcher/tenant/:tenant_id/quota`(新增路径草案) | `resource=tenant_quota`,分给该 D 的租户并发份额 | 拿到任务 tenant_id 后读取,同租户任务共享,缓存最多约60秒且不超过有效截止 | 缺失/过期/错身份停该租户新准入,额度0不影响stop静默排空 |
SIP `200` 响应的 `schema_version` 固定 `config-read.v0.2`,其余配置响应继续使用 `config-read.v0.1`,`resource` 区分 SIP、任务及租户额度结构,`dispatcher_id` 必须等于 Header 中的 D。**不使用条件请求、ETag 或 `304`**:到期时重新 GET 完整响应;只有收到、验证并重新确认授权有效后才更新缓存。SaaS 变更到 D 的目标延迟约 60 秒;缓存到期且刷新失败,**不可无限期沿用旧版本发起新呼叫**。MQ 停/暂停不等待这 60 秒。已接纳/已接通呼叫固定自己的快照,不因缓存过期而漂移。
非 `200` 返回 `resource=error`、`error.code`、`error.message` 的脱敏 JSON(HTTP 状态与 code 按本节约定;真实 SaaS 是否一致尚未验证),不得吞成旧配置/空任务。下一版 `call.execute.payload` **只有 `task_id` 与 `callee`**;D 从已批准的任务快照读取路由/主叫/智能体版本及任务级 `ring_timeout_ms/max_call_duration_ms`,接纳前持久绑定完整快照,不能从精简命令中猜值或悄悄采用过期缓存。现行严格 MQ Schema 尚未修改。
## 3. 任务成功响应:字段与来源
响应中的英文键**全部是本项目提议的返回键**,不是从截图抓到的 SaaS JSON。P/C/N 只说明其业务含义的依据:
| 返回位置 | 类型 / 是否必有 | 含义及来源 |
| --- | --- | --- |
| `dispatcher_id`, `tenant_id`, `tenant_key`, `task_id`, `task_revision` | UUID v4、租户ID、原值租户键、任务ID、正整数;必有 | C:当前命令及每 D/租户身份;N:任务固定归属一个 D,SaaS 必须持久保存 `(tenant_key,task_id)→dispatcher_id`;不得跨 D 投递。tenant_id 与原值 tenant_key 一对一映射,取得任务后按 tenant_id 读取本 D 租户额度,不能从 task_id 猜。`tenant_key` 需另验证 **≤196 UTF-8 字节**及路由段边界,Schema 的字符数不是字节数。 |
| `status` | `running/paused/stopped/finished`;必有 | P:页面可见启停状态;N:面向 D 的状态枚举是本项目暂定,不承诺与页面/实际 API 状态值同名。停/暂停需配合 MQ 控制屏障,不能只靠缓存。 |
| `name`, `group_id` | 提供时分别为非空字符串、字符串或 `null`;可缺省 | P:任务名称/所属分组。显示信息不参与拨号许可;`null` 与空字符串不混同。 |
| `max_concurrent_calls`, `ring_timeout_ms`, `max_call_duration_ms` | 正整数、正整数毫秒、正整数毫秒;必有 | P:任务并发;N:振铃及最长通话时间是**任务配置**,所有新接纳呼叫由同一获准任务快照取得,不由逐呼命令任意覆盖。通话有效上限取任务 max_call_duration_ms 与已授权 AI conversation.max_duration_ms 较小值,执行侧/AI控制器一致且不改原快照;并发另受租户份额、供应商/Cell/AI约束;截图里的“5”不是默认值。 |
| `route_policy_id`, `caller_profile_id`, `allowed_trunk_ids[]` | 路由标识、明确主叫引用、有序候选线路数组;必有 | N:route_policy_id标识本任务规则,不另引入未定义查询;按候选顺序选首个已加载、时段/额度有效且支持此主叫引用的线路,无匹配不接纳。主叫不默认取首个,线路/主叫选择后持久绑定,拨号失败/未知不自动换线。 |
| `schedule.time_zone`, `starts_at`, `ends_at` | 固定 `Asia/Shanghai`、带偏移时间或 `null`;必有 | P:任务起止时间;N:三字段格式/无值约定。时间约束与星期段、排除日期、线路时段**同时成立**。 |
| `schedule.weekly_windows` | 七个星期键各为可空的时间段数组;必有 | P:周一至周日网格、同日多个时段;N:`{start,end}` 用 `HH:MM`,左闭右开,`start < end`,跨午夜拆到次日,不假定 UI 已有这个 JSON 结构。空数组=当天不可呼。 |
| `schedule.excluded_dates[]` | 不重复的 `YYYY-MM-DD` 数组;必有,可为空 | N:用户新增的可选多日期排除(截图**没有**此字段)。日期按 Asia/Shanghai 判断并优先于星期段;真实日期、时段排序/重叠与边界须在业务校验中处理。 |
| `agent.agent_version_id`, `config` | ID、严格 AI 对象;必有 | P:任务选择 AI 模型/智能体;C:现有不可变 `agent_version_id` 和[AI Schema](../../contracts/upstream/v1/ai-config.schema.json)。不再返回 `content_sha256`;同版本不得变内容的检查应基于版本绑定及本地持久快照,不能悄悄接受漂移。`config` 原样遵守该现有 Schema,不把截图未覆盖参数偷塞 `metadata`。 |
| `agent.authorization_id`, `authorization_expires_at` | 非空 ID、带偏移时间;必有 | C:当前 MQ AI 授权含关联 ID 和有效期;N:嵌入任务 HTTP 响应的承载位置新设计,过期不可新接纳。 |
`agent.config` 当前可承载的**运行字段**:`mode`;ASR 的 `provider_ref/model/language/interim/input/timeout_ms`;LLM 的 `provider_ref/credential_ref/model/temperature/max_tokens/timeout_ms`;`prompt.text/allowed_variables/max_bytes`;TTS 的 `provider_ref/credential_ref/model/voice/speed/format/timeout_ms`;`conversation.opening/allow_interrupt/silence_timeout_ms/max_duration_ms/max_turns/sentence_max_chars/max_pending_audio_chunks` 等以**现有 AI Schema 本身为准**。`asr_only` 与 `full_ai` 两种模式均须按 Schema/SDK 能力分别校验;提示词不得出现在示例或日志中的真实用户文本。`agent.agent_version_id` 必须等于 `agent.config.agent_version_id`;授权身份及截止时间必须单独核验,不通过额外 `content_sha256` 字段证明授权。
新call.execute没有逐呼variables来源;需要未提供变量的提示词必须拒绝或在F01先补获批来源,不能填空继续执行。状态来源按总计划§3.3:stopped不可逆、paused只能经最新有效resume解除;任务缓存和tasks增量的旧running不能解锁。
### 3.1 页面观察但不作为 D 运行字段
| 原页面可见项 | 归属判断 / 暂不返回原因 |
| --- | --- |
| 智能体名称/描述、草稿/提交、文字/语音/线路测试 | SaaS 管理页面元数据/测试入口,不能代替 `agent_version_id` 的已发布运行快照。 |
| 提示词编辑器工具、独立开场白、挂断触发/结束语 | `prompt.text` 与 `conversation.opening` 可映射当前合同;挂断条件与结束语尚无当前严格 AI 字段,不能猜到通话控制里。 |
| ASR 页面 PCM/Opus/AAC/OGG/WAV、标点、去语气词、单句时长 | 当前合同支持的输入为 `pcm_s16le` 等已定义值;其它编码及三个开关/时长需先验证媒体和 SDK,并修订 GAP-09/新合同。 |
| LLM 对话模式、Top-P、重复惩罚、Top-K、随机种子、思考/流式开关 | 模型/温度等已有字段可用;其余没有获批准的运行字段及参数能力 PoC,**不进入 HTTP 的 `agent.config`**,不静默忽略后宣称已生效。 |
| TTS 公共/个人音色、情绪、音调、MP3/WAV 选项、试听 | 已有 `voice/speed/format` 可按实际能力承载;其它参数和试听不直接映射现有 Agent 可执行配置。 |
| 话后分析提示词及 A–F 意向规则 | 页面可见但当前 AI 快照没有对应执行和结果契约;仍由 SaaS 负责或另行定义,不能伪装成外呼 Agent 参数。 |
| 任务拨打顺序/时间间隔、自动重呼及次数/条件、结束动作、黑名单组、备注 | P:页面有这些项;本接口只返回 D **当前已获授权且有实现责任**的准入信息。排序、间隔、名单/运营策略应由 SaaS 明确负责;自动重呼不得伪装成 MQ 重投或 D 的自动再拨。 |
| 导入号码、号码列表、统计、通话记录、意向图表 | 属单次 `call.execute`/SaaS 展示与运营事实,不能一次塞进“任务配置”返回;不能从截图冻结数据页的 API 列名和返回结构。 |
这些字段**已在字段盘点中固化存在性和缺口**,不是声称 SaaS 已有相应返回键。若用户明确要求其中某项由 D/Agent 执行,先核实上游模型/SDK、增加获批准的严格字段及正反例,不在新接口中以 `metadata` 或 raw JSON 穿透。
## 4. SIP 成功响应:字段与来源
| 返回位置 | 类型 / 是否必有 | 含义及来源 |
| --- | --- | --- |
| `dispatcher_id`, `revision`, `approved_at` | UUID v4、正整数、带偏移时间;必有 | N:指定 D 的完整获批 SIP 线路版本。每次内容变化递增 revision;相同版本内容漂移及版本倒退必须拒绝。 |
| `trunks[]` | 严格数组;必有 | N:单份获批线路清单;每项含 `trunk_id/provider_id/egress_pool_id/codec/dial_prefix/enabled`、服务端、鉴权、主叫、额度及每周时段。线路 ID 和同线路主叫引用不得重复。前缀只用于本线路,主叫保留原值(可含字母);PCMA 仍须实际线路验证。 |
| `server_host`, `server_port`, `transport` | 主机/端口、`udp/tcp/tls/null`;必有 | N:补足“全量 SIP”需要的实际对端;页面仅显示任务选线路,**没有管理线路完整配置截图**。供应商传输未知时为 `null`,绝不擅自按 UDP 默认发起 real。mock 示例地址非真实供应商。 |
| `auth_mode`, `registration_required` | `ip/digest/none/null`、`true/false/null`;必有 | N:供应商鉴权/注册未知时 `null`,不得把主叫号当 Digest 账号;real 放行前须供应商/management 批准并验证。不返回密码、私钥或真实 TOKEN。 |
| `max_concurrent_calls` | 正整数或 `null`;必有 | N:线路/供应商获批份额,`null` 表示未知(real 必须拒绝新准入),不能拿截图任务“线路数量”猜限额;跨 D 份额总和须受源配额约束。 |
| `caller_profiles[]` | `{caller_profile_id, caller_id}` 数组;必有 | C:旧制品仅有 profile ID;N:全量响应映射 profile→原样主叫标识。From/PAI 具体映射仍待供应商确认;示例主叫是 mock,不是生产号。 |
| `schedule.time_zone`, `weekly_windows` | `Asia/Shanghai`,七天逐日零或多个时段;必有 | N:SIP 线路允许拨打时段(截图未提供),与任务时段相交;无允许段则不能呼叫。时间跨午夜拆到次日,结果还受 Agent 最后拨号门禁约束。 |
SaaS 只提供 SIP 连接和线路拨号约束,不下发 Agent/Asterisk 的部署参数、静态 Cell 制品、运行模式或全局号码白名单。部署参数及 Cell 身份由本地受控配置核对。management 仍是 SIP 唯一编辑/审批面,SaaS 必须分发同一获批版本。D 从 Agent 实际运行状态核对已加载的 SIP revision;HTTP `200` 及仅收到配置不代表已生效。示例 `transport/auth_mode/registration_required/max_concurrent_calls=null` 是供应商待确认项,**不满足 real 放行**。
## 4.1 租户额度响应(项目内新增字段 N,外部未签收)
| 字段 | 类型/约束 | 业务语义 |
| --- | --- | --- |
| schema_version/resource | config-read.v0.1 / tenant_quota | 项目草案,不是现网版本。 |
| dispatcher_id/tenant_id/tenant_key | D UUID、租户ID、原值租户键,必有 | 与请求、任务、信封一致,SaaS一对一映射;错误不猜值。 |
| quota_revision | 正整数,必有 | 本D租户额度版本,旧版本不覆盖新分配。 |
| max_concurrent_calls | 非负整数,必有 | 本D同租户所有任务共用份额,0禁止新呼叫;不是每任务分别上限。 |
| valid_until | RFC3339时间,必有 | 截止后不得新准入,本地缓存最多约60秒且不得越过此时刻。 |
D 在同一事务预留租户/任务/线路等占用,未知继续计入;降额不强挂、占用低于新上限才再接新。额度缺失、过期/错身份、刷新失败关闭新准入,不能以任务额度代替。已确认通话终结/执行资源释放即可释放通话额度,不等录音上传或MQ确认;stop静默ACK不需申请通话名额。多D须由SaaS分份额,累计不超过租户总额;本轮只验证单D。
## 5. 外部待核事项(不阻塞本地 F01/C)
1. **外部来源与审批:**真实 SaaS/management 联调前,确认 SaaS 的任务、智能体是该服务的权威配置;management 仍是唯一 SIP 编辑/审批方。证明 SaaS 分发的是 management 已批准的完整 SIP 线路版本,不能出现两份可写配置。此项不阻塞本地 Mock。
2. **身份和响应:**本地请求头为 `X-DISPATCHER-id` 与 `X-DISPATCHER-SECRET-KEY`;只读取归属 D 的 `/internal/v1/dispatcher/sip`、`/internal/v1/dispatcher/tasks`、`/internal/v1/dispatcher/task/:task_id` 和 `/internal/v1/dispatcher/tenant/:tenant_id/quota`,不在日志/示例保存真实密钥。身份校验、状态码与生效时间按本文件和第三方对接契约作为本地规则;真实 SaaS 兼容性未验证。不采用 `ETag`/`304`。
3. **窗口与版本:**本地缓存成功核验起约 60 秒;SaaS 变更对未接纳呼叫最多约 60 秒延迟,过期重新 GET 完整数据失败就停止新准入,已接纳保留原快照。更新/SIP 加载期间停执行队列,不停控制 MQ;停/暂停不等缓存。没有 `304` 延长授权的通道。跨日窗口、重叠段、当日排除、时间边界及任务与线路交集按本地 Schema/业务测试执行;真实 SaaS 行为未验证。
4. **一致性:**`agent_version_id` 与 AI 授权一致且有效,同版内容漂移必须拒绝;任务归属/修订/route policy 以已绑定任务快照为准,MQ 命令不得覆盖;`trunks` 中线路 ID/主叫引用唯一;线路 status、主叫、前缀、线路/租户/供应商额度来源和 Agent/Asterisk 实际加载不可依赖 JSON Schema 单独判断。供应商未知传输/鉴权/注册不得默认允许 real。
5. **消费状态:**pause保留原队列积压,resume最新配置/授权/额度有效才继续消费,无需SaaS重新投递;新版命令不带 `not_after`,积压外呼仍须在接纳和拨号前重新核验时段及授权。stop后未接纳积压静默消费ACK,不拨号、不发逐条回执/最终结果;控制本身与已在途通话结果仍回传,本地计数/错误不静默。状态优先级及例外按总计划§3.3,不加控制去重。
6. **退出与过渡:**新接口上线前现行 MQ-only/单 D/固定时段/静态 SIP 仍有效。切到新版本后配置只走 HTTP,旧 `ai.config.request/result` 停用,不做 HTTP→MQ 回退;业务 MQ 正常运行。多 D 任务归属/共享额度份额、旧命令/缓存/恢复记录和控制屏障须单独验证;任务结束只删除配置缓存,不删除未决执行与消息事实。
**验证状态:**本地 JSON Schema 草案包含 SIP、任务、租户额度 `200` 成功响应、有效错误响应及一个额外字段非法样例;只有 Schema 校验通过的有效示例可作为正例,非法样例必须被拒绝。此离线校验**不能**证明真实 SaaS 接口字段名、management 签收、hash 规范、Agent SDK 映射、SIP 实际加载或任何生产外呼验收。