docs: refine task controls and tenant quota contracts

This commit is contained in:
2026-09-23 20:27:51 +08:00
parent 6e29ac87ac
commit ef84a0663d
8 changed files with 453 additions and 247 deletions
@@ -1,4 +1,4 @@
# 两条只读配置接口:任务、智能体、SIP 字段与返回结构 v0.1(项目提案)
# 只读配置与租户额度接口:任务、智能体、SIP 字段与返回结构 v0.1(项目提案)
**状态:项目自定义草案,非 SaaS 已有接口/实际 JSON、非已发布契约、非实现/验收。** 用户同意:截图可见的业务含义先映射为**项目定义的字段名**;截图没有但需求明确的结构由本项目设计。即使字段名与现有项目 Schema 或历史 OpenAPI 相同,也**不能**据此声称它是当前 SaaS 页面原有的后端键。SaaS 和 management 在 W01 签收前不得据此开始真实配置发布/拨号。
@@ -8,20 +8,21 @@
- **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 响应证据**。旧 [OpenAPI/MQ 只读索引](../references/OpenAPI与MQ字段索引_v0.1.md) 也仅为历史参考。
- **N = 新项目字段:**任务每周多时段/排除日期、SIP 线路时段、任务与单 D 绑定、缓存/版本/错误返回等,由本提案定义;实际 SaaS 接口不存在已验证响应。
交付物:[机器可读响应草案](config-read-v0.1.schema.json)、[mock SIP 成功示例](examples/config-read-sip-v0.1.json)、[mock 任务成功示例](examples/config-read-task-v0.1.json)。两条接口均为 **SaaS→Dispatcher 的只读 HTTP 配置读取**;MQ 继续单独承担呼叫、控制、查询、上传事实与业务结果,不留旧 AI/SIP 配置 MQ 回退。**接口路径、UUID+SECRETKEY 承载位置、错误码的准确枚举、哈希计算规范及 SaaS/management 实际来源仍需 W01 冻结**,本文件不冒充外部权威发布物。
交付物:[机器可读响应草案](config-read-v0.1.schema.json)、[mock SIP 成功示例](examples/config-read-sip-v0.1.json)、[mock 任务成功示例](examples/config-read-task-v0.1.json)、[mock 租户额度示例](examples/config-read-tenant-quota-v0.1.json)。前两条接口为**拟定的只读 HTTP 配置读取**:`GET /internal/v1/dispatcher/sip` 与 `GET /internal/v1/dispatcher/task/:task_id`;下一轮另拟 `GET /internal/v1/dispatcher/tasks` 和 `?after=<cursor>` 发现归属任务;新增项目拟定 `GET /internal/v1/dispatcher/tenant/:tenant_id/quota` 按任务的租户 ID 读取本 D 的租户份额。四条请求携带 `X-DISPATCHER-id`(D UUID)及 `X-DISPATCHER-SECRET-KEY`(受控密钥),无请求体;实际 SaaS 实现仍待签收。业务呼叫/控制及回执/最终结果继续走 MQ,目标版本移除对外查询/补传;不留旧 AI/SIP 配置 MQ 回退。**HTTP 响应错误码、SIP 快照规范及 SaaS/management 实际来源仍需 W01/F07 冻结**,本文件不冒充外部权威发布物。
## 2. 请求与共同响应
Dispatcher 使用其**全局唯一 UUID**和部署受控的 **SECRETKEY**,仅查询自己管理的资源分区和归属任务;不记录完整密钥或返回配置中的提示词。接口只读、无启动/停止/修改副作用。准确 URL、请求参数/头、SaaS 对任务归属的核验、密钥轮换时序由双方签收;本文仅固化响应的**项目字段草案**,不推测 SaaS 已有 API 路径。
Dispatcher 仅用 `X-DISPATCHER-id`(全局唯一 UUID)和部署受控的 `X-DISPATCHER-SECRET-KEY` 请求归属资源;不记录密钥或在日志中打印配置提示词。接口只读、无控制副作用;SaaS 必须核验任务归属。Header 的准确校验、密钥轮换时序、HTTP 错误状态仍需 SaaS 签收。`GET /internal/v1/dispatcher/tasks`(含 `?after=<cursor>`)是**第三条待 F07 签收的任务发现接口**,其快照/变更示例见[第三方对接 §2.5](../thirds/第三方对接事件与请求消费顺序_v0.1.md),不混入本文件的配置响应 Schema;第四条租户额度响应属于本文件新增草案,路径/字段未获 SaaS 签收。
| 请求 | `200` 返回类型 | 何时读取 | `304` 与错误 |
| 请求 | `200` 返回类型 | 何时读取 | 错误处理 |
| --- | --- | --- | --- |
| SIP 全量配置 | `resource=sip_config`,一个 D 资源分区的已批准完整快照 | 新 D/重启先取齐并核对 Agent/Asterisk 精确加载;运行中约每 60 秒核对版本 | 未变且仍获批准可 `304`(空响应体);读取错误/到期停止新执行准入,旧活动通话依原快照排空 |
| 单任务配置(内含智能体) | `resource=task_config`,归属 D 的单任务有效配置和已授权智能体快照 | 有待接纳呼叫时获取,活跃任务缓存约 60 秒、到期主动复核,不逐呼下载整份配置 | 未变且授权仍有效可 `304`;失败/过期不以旧缓存放行新执行;已接纳执行仍用原快照 |
| `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静默排空 |
`200` 响应中的 `schema_version` 固定 `config-read.v0.1`,`resource` 区分两种结构,`dispatcher_id` 必须等于请求 D;HTTP `ETag` 标识**完整有效决策**,并非某个 UI 表单的草稿版本。`If-None-Match` 命中时 `304` **没有 JSON 响应体**;只有此前的批准状态、任务归属及 AI 授权仍足以覆盖下一次缓存有效期,才可延长本地缓存,否则返回 `200` 新快照或明确失败。SaaS 实际更新到 D 允许最多约 60 秒延迟;一旦缓存到期且刷新失败,**不可无限期沿用旧版本发起新呼叫**。MQ 停/暂停、opt-out 不等这 60 秒。已接纳/已接通呼叫固定自己的快照,不因本地配置缓存过期而变更。
`200` 响应中的 `schema_version` 固定 `config-read.v0.1`,`resource` 区分 SIP、任务及租户额度结构,`dispatcher_id` 必须等于 Header 中的 D。**不使用条件请求、ETag 或 `304`**:到期时重新 GET 完整响应;只有收到、验证并重新确认授权有效后才更新缓存。SaaS 变更到 D 的目标延迟约 60 秒;缓存到期且刷新失败,**不可无限期沿用旧版本发起新呼叫**。MQ 停/暂停不等待这 60 秒。已接纳/已接通呼叫固定自己的快照,不因缓存过期而漂移。
非 `200/304` 返回 `resource=error`、`error.code`、`error.message` 的脱敏 JSON(HTTP 状态及 code 逐项待 SaaS 确认);不得将错误吞成旧配置/空任务。原始 `call.execute` 的 `task_revision`、`agent_version_id`、`route_policy_id` 与后续新版本可能不同;如何让未接纳执行合法采用新版本、变更与接纳并发时何时冻结版本,**尚需版本化 MQ/HTTP 合同约定,不可静默改写原命令**。
非 `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. 任务成功响应:字段与来源
@@ -29,18 +30,20 @@ Dispatcher 使用其**全局唯一 UUID**和部署受控的 **SECRETKEY**,仅
| 返回位置 | 类型 / 是否必有 | 含义及来源 |
| --- | --- | --- |
| `dispatcher_id`, `tenant_key`, `task_id`, `task_revision` | UUID v4、原值字符串、字符串、正整数;必有 | C:当前命令及每 D/租户身份;N:任务固定归属一个 D,SaaS 必须持久保存 `(tenant_key,task_id)→dispatcher_id`;不得跨 D 投递。`tenant_key` 需另验证 **≤196 UTF-8 字节**及路由段边界,Schema 的字符数不是字节数。 |
| `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` | 正整数;必有 | P:任务并发。仅限制**该任务**,另须服从 D 的租户份额、供应商、Cell 和 AI 配额。截图里的“5”是某次输入,不是默认值。 |
| `route_policy_id`, `allowed_trunk_ids[]` | 非空字符串、至少一条线路 ID;必有 | C:`route_policy_id` 已在命令;P:选择启用线路。N:`allowed_trunk_ids` 是本项目定义的白名单,须与已加载 SIP 制品的 `trunk_id` 对齐;不能把任务页面“每条线路数量”直接猜成运营商并发上限。 |
| `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`, `content_sha256`, `config` | ID、64位小写 hex、严格 AI 对象;必有 | P:任务选择 AI 模型/智能体;C:现有不可变 `agent_version_id`、`content_sha256` 和[AI Schema](../../contracts/upstream/v1/ai-config.schema.json)。`config` 原样遵守该现有 Schema,不把截图未覆盖参数偷塞 `metadata`。 |
| `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` 的摘要生成规范/与现有 AI 授权摘要对齐前不可声称验签通过。
`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 运行字段
@@ -73,12 +76,25 @@ Dispatcher 使用其**全局唯一 UUID**和部署受控的 **SECRETKEY**,仅
静态制品中的端点**引用**与此提案补充的对端**值**属于同一获批版本;若 SaaS 与 management 并非同一配置来源,必须证明它们同步一致,且 Agent/Asterisk 实际加载的版本/摘要匹配。`artifact.load_evidence` 为 `null` 只表示 HTTP 获得配置,**不代表 Asterisk 已加载**;D 必须另从实际执行侧核验。样例 `mode=mock`、`transport/auth_mode/registration_required/max_concurrent_calls=null` 是故意保留的供应商待确认项;**不满足 real 放行**。只提供SaaS读接口却不能取得已批准的端点及线路时段,不得声称已经提供了完整 SIP 配置。
## 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. 需冻结的语义与验收前置
1. **来源:**确认 SaaS 的任务、智能体是该服务的权威配置;management 仍是唯一 SIP 编辑/审批方。确认 SaaS 分发的是已批准制品与线路补充字段同一版本,不能出现两份可写配置。
2. **身份和响应:**D 的 UUID+SECRETKEY 只能读取获分配的资源分区及任务;不在日志/示例保存真实密钥。精确 HTTP 路径、请求参数/头、鉴别方式、状态码、`ETag` 粒度与生效时间由 SaaS 正式签收。
3. **窗口与版本:**缓存成功核验起约 60 秒;SaaS 变更对未接纳呼叫最多约 60 秒延迟,过期刷新失败停止新准入,已接纳保留原快照。更新/SIP 加载期间停执行队列,不停控制 MQ;停/暂停与 opt-out 不等缓存。`304` 不得延长已撤销或即将过期的 AI 授权。跨日窗口、重叠段、当日排除、时间边界以及任务与线路交集需在业务校验并在新合同定稿时冻结。
4. **一致性:**`agent_version_id`、摘要、AI 授权一致且有效;任务归属/修订/route policy 与已发布命令如何重新授权;`artifact.trunks` 与 `trunk_details` 一一对应;线路 status、主叫、前缀、媒体、线路/租户/供应商额度来源和 Agent/Asterisk 实际加载不可依赖 JSON Schema 单独判断。供应商未知传输/鉴权/注册不得默认允许 real。
5. **退出与过渡:**新接口上线前现行 MQ-only/单 D/固定时段/静态 SIP 仍有效。切到新版本后配置只走 HTTP,旧 `ai.config.request/result` 停用,不做 HTTP→MQ 回退;业务 MQ 正常运行。多 D 任务归属/共享额度份额、旧命令/缓存/恢复记录和控制屏障须单独验证;任务结束只删除配置缓存,不删除未决执行与消息事实。
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` 延长授权的通道。跨日窗口、重叠段、当日排除、时间边界及任务与线路交集须在合同冻结。
4. **一致性:**`agent_version_id` 与 AI 授权一致且有效,同版内容漂移必须拒绝;任务归属/修订/route policy 以已绑定任务快照为准,MQ 命令不得覆盖;`artifact.trunks` 与 `trunk_details` 一一对应;线路 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 草案可校验两个 mock `200` 示例及非法样例;它**不能**证明真实 SaaS 接口字段名、管理平台签收、hash 规范、Agent SDK 映射、SIP 实际加载或任何生产外呼验收。
**验证状态:**本地 JSON Schema 草案覆盖 SIP、任务和新增租户额度 `200` 示例及错误/非法样例;它**不能**证明真实 SaaS 接口字段名、管理平台签收、hash 规范、Agent SDK 映射、SIP 实际加载或任何生产外呼验收。
+22 -3
View File
@@ -5,6 +5,7 @@
"oneOf": [
{"$ref": "#/$defs/sip_response"},
{"$ref": "#/$defs/task_response"},
{"$ref": "#/$defs/tenant_quota_response"},
{"$ref": "#/$defs/error_response"}
],
"$defs": {
@@ -29,11 +30,12 @@
"task_response": {
"type": "object",
"additionalProperties": false,
"required": ["schema_version", "resource", "dispatcher_id", "tenant_key", "task_id", "task_revision", "status", "name", "group_id", "max_concurrent_calls", "route_policy_id", "allowed_trunk_ids", "schedule", "agent"],
"required": ["schema_version", "resource", "dispatcher_id", "tenant_id", "tenant_key", "task_id", "task_revision", "status", "name", "group_id", "max_concurrent_calls", "ring_timeout_ms", "max_call_duration_ms", "route_policy_id", "caller_profile_id", "allowed_trunk_ids", "schedule", "agent"],
"properties": {
"schema_version": {"const": "config-read.v0.1"},
"resource": {"const": "task_config"},
"dispatcher_id": {"$ref": "#/$defs/dispatcher_id"},
"tenant_id": {"type": "string", "minLength": 1, "maxLength": 128},
"tenant_key": {"type": "string", "minLength": 1, "maxLength": 196, "$comment": "Also validate <=196 UTF-8 bytes and routing word boundaries using the project-owned tenant contract."},
"task_id": {"type": "string", "minLength": 1, "maxLength": 128},
"task_revision": {"type": "integer", "minimum": 1},
@@ -41,12 +43,30 @@
"name": {"type": "string", "minLength": 1, "maxLength": 256},
"group_id": {"type": ["string", "null"], "maxLength": 128},
"max_concurrent_calls": {"type": "integer", "minimum": 1},
"ring_timeout_ms": {"type": "integer", "minimum": 1},
"max_call_duration_ms": {"type": "integer", "minimum": 1},
"route_policy_id": {"type": "string", "minLength": 1, "maxLength": 128},
"caller_profile_id": {"type": "string", "minLength": 1, "maxLength": 128},
"allowed_trunk_ids": {"type": "array", "minItems": 1, "maxItems": 32, "uniqueItems": true, "items": {"type": "string", "minLength": 1, "maxLength": 128}},
"schedule": {"$ref": "#/$defs/task_schedule"},
"agent": {"$ref": "#/$defs/agent"}
}
},
"tenant_quota_response": {
"type": "object", "additionalProperties": false,
"required": ["schema_version", "resource", "dispatcher_id", "tenant_id", "tenant_key", "quota_revision", "max_concurrent_calls", "valid_until"],
"properties": {
"schema_version": {"const": "config-read.v0.1"},
"resource": {"const": "tenant_quota"},
"dispatcher_id": {"$ref": "#/$defs/dispatcher_id"},
"tenant_id": {"type": "string", "minLength": 1, "maxLength": 128},
"tenant_key": {"type": "string", "minLength": 1, "maxLength": 196},
"quota_revision": {"type": "integer", "minimum": 1},
"max_concurrent_calls": {"type": "integer", "minimum": 0},
"valid_until": {"type": "string", "format": "date-time"}
},
"$comment": "PROPOSAL: SaaS-assigned share for this Dispatcher; aggregate all tasks of the tenant. Validate tenant_id/tenant_key mapping and expiry in business checks."
},
"error_response": {
"type": "object",
"additionalProperties": false,
@@ -96,10 +116,9 @@
},
"agent": {
"type": "object", "additionalProperties": false,
"required": ["agent_version_id", "content_sha256", "authorization_id", "authorization_expires_at", "config"],
"required": ["agent_version_id", "authorization_id", "authorization_expires_at", "config"],
"properties": {
"agent_version_id": {"type": "string", "minLength": 1, "maxLength": 128},
"content_sha256": {"$ref": "#/$defs/sha256"},
"authorization_id": {"type": "string", "minLength": 1, "maxLength": 128},
"authorization_expires_at": {"type": "string", "format": "date-time"},
"config": {"$ref": "https://go-sip.local/contracts/v1/ai-config.schema.json"}
@@ -2,6 +2,7 @@
"schema_version": "config-read.v0.1",
"resource": "task_config",
"dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6",
"tenant_id": "tenant-id-mock",
"tenant_key": "tenant-mock",
"task_id": "task-mock",
"task_revision": 2,
@@ -9,7 +10,10 @@
"name": "Mock task",
"group_id": null,
"max_concurrent_calls": 2,
"ring_timeout_ms": 30000,
"max_call_duration_ms": 120000,
"route_policy_id": "route-mock",
"caller_profile_id": "caller-profile-mock",
"allowed_trunk_ids": ["trunk-mock"],
"schedule": {
"time_zone": "Asia/Shanghai",
@@ -28,7 +32,6 @@
},
"agent": {
"agent_version_id": "agent-version-mock",
"content_sha256": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"authorization_id": "auth-mock",
"authorization_expires_at": "2026-09-21T18:00:00+08:00",
"config": {
@@ -0,0 +1,10 @@
{
"schema_version": "config-read.v0.1",
"resource": "tenant_quota",
"dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6",
"tenant_id": "tenant-id-mock",
"tenant_key": "tenant-mock",
"quota_revision": 1,
"max_concurrent_calls": 3,
"valid_until": "2026-09-21T18:00:00+08:00"
}