merge: W23 —— 接入契约 v0.63 的 documents[].reason(只在下发时原样显示,不做整句判断)

This commit is contained in:
AskaEth committed 2026-10-04 22:08:06 +08:00
commit 2d382b11cd
7 files changed
+269 -8

No files matched your search

@@ -25,6 +25,8 @@ import kotlinx.serialization.Serializable
* 3. 下行/历史元素只回**引用与统计,绝不回正文**(吸取 `G3`「base64 原样落库、每页历史重传」
* 的教训)。`status:"unreadable"` 才是「读不到这个文件」的可观测信号,**不是** `truncated`
* (`truncated` 只说明注入正文被预算截断,正文照样进得了上下文)。
* **契约 v0.63(后端 `902b6ee`)在此之上加了可选 [DocumentRefDto.reason]**:读不到时随
* `status:"unreadable"` 一起下发的**服务端原话**,客户端原样显示(详见该字段的 KDoc)。
*
* ## 客户端必须两种都吃的一件事
* 「0 个附件」这一形状在后端**尚未定死**(回执五原文:期望「不出现或空数组」,S3.5 回报里定死)。
@@ -58,8 +60,8 @@ data class DocumentUploadResponse(
* 下行/历史则带上全部统计字段。
*
* 字段可出现性(后端 `history.DocumentRef` 的 `omitempty` 口径,逐字段核对过):
* `name` / `mime` / `size` **恒在**;`chars` / `truncated` / `status` 为 Go 的 `omitempty`
* —— 零值(0 / false / "")时**整键省略**,所以取值一律给默认值,解码不会因缺键失败。
* `name` / `mime` / `size` **恒在**;`chars` / `truncated` / `status` / `reason` 为 Go 的 `omitempty`
* —— 零值(0 / false / "" / nil)时**整键省略**,所以取值一律给默认值,解码不会因缺键失败。
*/
@Serializable
data class DocumentRefDto(
@@ -80,4 +82,18 @@ data class DocumentRefDto(
* 未知值**原样保留**(不丢弃、不报错、不占位符),由客户端决定如何显示。
*/
val status: String = "",
/**
* **读不到的原因**(契约 v0.63 新增,后端 `902b6ee`):`status == "unreadable"` 时下发的
* 那句**服务端原话**;`status == "extracted"` 时**整键缺席**,因此是可选字段。
*
* 两句纪律:
* 1. **原样显示**。[reason] 与后端**注入模型清单里的那 10 条是同一份字符串**(逐字相同,
* 最长的一条 40+ 字),客户端**不替服务端改写、不截断、不归纳**成自己的话——
* 本端能编的只有像 [top.yeij.cyrene.domain.chat.DocumentPreviewGate.refusalMessage]
* 那样「按类型泛泛说一句」,比这里的原因粗得多;
* 2. **绝不做整句相等判断**。分类若真的需要分支,只允许用**稳定子串**(如「需要 OCR」)——
* 整句比对会在后端改一个字时静默失效,且失败的样子是「显示成兜底那句话」,
* 看起来完全正常。
*/
val reason: String? = null,
)