docs(contract): v0.84 —— 显示名形状变更 + 段落标签硬约束 + 浏览器降级档登记
① plugin.providers 候选:裸字符串数组 → 对象数组 {value,label};两条硬口径
(label 仅供显示、value 才是落盘值;前端三形状兼容 ⇒ 其他插件零影响)。
② 新增 §4.16:助手文本不得出现未配对段落标签(一个 <p> = 一段、段落不嵌套),
含实测根因两条 + 修后处置口径 + 「客户端仍应保留容错」与护栏清单。
③ 模型面登记:web-fetch 浏览器降级档的 fetchedBy(direct|browser)如实标注。
④ provider 配置面去 env 化(对客户端零形状影响)一并登记。
⑤ 计数不变:无新端点 ⇒ 14 + 24 + 40 = 78。
顺带修一处我自己的失误:上一版登记 §4.15 时把 `## 5. env 与模型配置` 标题
误删,已补回(§5 表格内容未受影响)。
诚实边界:web-search 真机工具路径仍有一处未部署的修复(linkless)已登记;
显示名真机点击未跑 + dist 是 go:embed(前端改动必须重新 build);
viewer 角色表格仍显示裸 id;腾讯/秘塔适配未实现。
This commit is contained in:
1 parent
2c56bc9704
commit
77dbf9b1f7
1 file changed
+50
-4
+50
-4
@@ -1,6 +1,6 @@
|
||||
# Cyrene v2 客户端 API 契约
|
||||
|
||||
> **契约版本:`v0.83`**(上一版 `v0.82`,其条目见 §6;`v0.81` / `v0.80` / `v0.79` / `v0.78` / `v0.77` / `v0.76` / `v0.75` / `v0.74` / `v0.73` / `v0.72` / `v0.71` 及更早见本文件 §6,`v0.67` 及更早的基线已归档、只读:`Docs/archive/api-client.v0.65.md`)。
|
||||
> **契约版本:`v0.84`**(上一版 `v0.83`,其条目见 §6;`v0.82` / `v0.81` / `v0.80` / `v0.79` / `v0.78` / `v0.77` / `v0.76` / `v0.75` / `v0.74` / `v0.73` / `v0.72` / `v0.71` 及更早见本文件 §6,`v0.67` 及更早的基线已归档、只读:`Docs/archive/api-client.v0.65.md`)。
|
||||
> **读者**:Web 前端 / 移动端原生客户端(含 Android)/ IM 桥接等**跨平台客户端开发者**。
|
||||
> **唯一真源 = 当前代码**(`internal/services/gateway/*` 等)。本文档由代码逐条核对得出;与代码不符时**以代码为准**,并回改本文档。
|
||||
> **旧的超详细版已归档、只读**:`Docs/archive/api-client.v0.65.md`(412 KB,含 v0.28→v0.65 全部历史条目)与 `Docs/archive/api-reference.v0.65.md`(170 KB,后端全量字段级文档)。归档的原因是**结构性臃肿 + 历史条目并列 + 长期漂移**;本文档**不复制**那段历史,需要考古时去归档。
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
> **v0.77 是链路图按路分桶 + 记忆整理护栏/异步落地版(已实现;纯增量)**:① **`graph_update` 按路分桶**(切片 FV2)—— 帧 `data` 新增可选 `turnId`(该图的**路**的权威回合标识)与 `round`(会话轮次号);真并行(`parallel:true`)时同一会话**每一路各发自己的帧**(`data.id` / `data.turnId` 各不相同),两路不再互相顶掉;`GET /api/v1/admin/flow/graph` 响应新增 `lanes[]`(**最近一轮每一路**的图,恒为非 null 数组),`graph` 语义不变(最新一路 / 指定轮 / `null` 诚实空态)⇒ **老的读取方零改动**。**无破坏性变更**(两个新键可选;单路时 `turnId` 缺席 ⇒ 客户端行为与 v0.75 逐字相同)。详见 **§2.2 B13 / §3.4.5 / §4.11 / §7.4-19**。② **记忆整理护栏抬高 + 诚实截断 + 试算异步落地**(切片 MT-A)—— 每分区候选上限 `MEMORY_TIDY_CANDIDATE_LIMIT` 默认值 `20 → 200`、两两比对上限改为 env 键新键 `MEMORY_TIDY_COMPARE_LIMIT`(默认 `2000`,原先**写死** `400`);配置事实面 **12 → 13 条**;`truncated` 新增第 4 种标签 **`(budget)`**(墙钟时间预算截断);**v0.76 ③ 的加性异步已落地**(`?async=1` + B15 轮询可用;新错误码 **`tidy_run_not_found`**)。详见 **§2.2 B14/B15 / §4.10(a) / §4.12 / §4.12.1 / §5**。③ **「入库前审查」的 4 个 env 键登记**(切片 MT-B,纯增量)—— `MEMORY_REVIEW_ENABLED`(`true`)/ `MEMORY_REVIEW_QUEUE_SIZE`(`256`)/ `MEMORY_REVIEW_SCAN_LIMIT`(`200`)/ `MEMORY_REVIEW_TIMEOUT_SEC`(`20`);⚠️ 该切片的**面板读侧 / 回滚端点目前没有 HTTP 入口**(见 §7.2)。详见 **§5**。
|
||||
|
||||
> **v0.84 是「显示名 + 段落标签硬约束」版(已实现并推库:`c46053e` 显示名 / `8051906` 段落修复 / `bc1dee3` provider 配置面去 env 化;**一处形状变更(插件动作响应)、一处新增硬约束;无破坏性变更**)**:① **`plugin.providers` 候选响应形状:裸字符串数组 → 对象数组 `{"options":[{"value":<id>,"label":<中文显示名>},…]}`**(§4.14(c))。修的是主人报障「中文搜索接口在管理后台下拉菜单里全给的英文名,你甚至不愿意带个括号把中文名写上去」—— 根因不是漏写文案,而是**整条链路没有「显示名」这个位置**(字段声明只有 `optionsFrom`,动作回的就是纯 id 数组)。🔴 **两条硬口径**:**(i) `label` 仅供显示,`value` 才是落盘值**(把 `label` 提交进 `provider` 会写坏配置文件);**(ii) 前端解码器兼容三种形状**(裸字符串 / `{value,label}` / `{id}`)⇒ 仍返回裸字符串的其他插件与老声明**零影响**。表格单元格按 `value→label` 索引显示、查不到回落原值;多选(降级链)改为「候选开关(显示 label、写 value)+ 落盘值输入框」。② **产出侧新硬约束(§4.16)**:助手文本(落库 / 对外 / IM 镜像)**不得出现未配对的段落标签**(落单 `<p …>` 或 `</p>`)—— `一个 <p> = 一段`,**段落不嵌套**。修的是安卓端登记的 `<p><p>正文</p>` 畸形(他们按非贪婪契约必然把 `<p>` 显示给用户);**实测两半都是产出侧造成**:规整器**原样放过**该形状,且会在「末段漏 `</p>`」时**亲手套出**它(并顺带修掉一个幂等漏洞:落单 `</p>` 会越跑越多)。🔴 **历史行不回填**,消费方**仍应保留**剥落单标签的容错。③ **模型面登记(非客户端契约面,供跨端对照)**:`web-fetch` 的**浏览器渲染降级档已接线**(`design/28 §1 M5 / §8 B5`),其返回体用 **`fetchedBy`**(`direct` / `browser`)**如实标注正文实际来自哪条路**,两条档的失败各自留痕(`browserError` / `directError`),**绝不静默替换**;被 SSRF 拒绝的目标**不换路**。④ **计数**:本版**无新端点** ⇒ §2.0 权限矩阵维持 **14 + 24 + 40 = 78**。⑤ ⚠️ **诚实边界**:**`web-search` 的真机工具路径在登记时仍有一处未部署的修复**(智谱对「热搜/资讯」类查询返回的条目 `link` 整批为空,旧判据把「无链接」当「不是结果」整批丢光 ⇒ 工具报 `no results` 而面板探针报 `ok` —— 因为探针**不过 `Finalize`**,对这一类缺陷**结构性失明**)。修复已推库(`2c56bc9`:无链接条目照原样保留、只有 link/title/content/snippet 全空的空壳行才不算结果),**要等下次 `build` + `restart` 才真机生效**。**教训登记**:**别拿面板探针通不通来推断工具路径通不通**。
|
||||
|
||||
> **v0.83 是记忆整理「应用面」版(已实现并推库:切片 TIDY-1 `454ddb0` + 读侧 status 闸 `9126d65` + 网关端到端回归 `f847769`;**纯增量、无破坏性变更**)**:① **新增 5 条 `writeAuth` 端点**,补上「整理只产建议、永远不落地」这个两天没闭环的缺口 —— **B20** `GET /api/v1/admin/memories/candidates`(候选列表)、**B21** `POST …/candidates/{id}/apply`(单条应用)、**B22** `POST …/candidates/apply?runId=&limit=`(批量应用;`runId` 省略 = **全部待定**)、**B23** `POST …/candidates/{id}/revert`(单条回滚)、**B24** `POST …/memories/tidy/run`(手动**真跑**一轮:写候选 + 留痕,**不自动应用**)。语义与形状见 **§4.15**。🔴 **三条硬口径(客户端按此编程)**:**(i) 幂等不是错误** —— 已决定过的候选回 `200` + `status:"skipped"`,界面**不得**画成失败;**(ii) 超限必须如实** —— 批量回执的 `total` 是**真正命中筛选的待定候选数**,而 `applied+skipped+failed` 只覆盖 `limit` 之内,两者不等时 `truncated:true`(不许把「本轮 100 / 共 342」画成「全部完成」);**(iii) 永不物理删除** —— merge / archive 都是**软动作**(只改 `status`,正文一个字不改、行一行不删),因此 `revert` 无损可逆。② **读侧 status 闸(行为修复,形状零变化)**:记忆的**四条列表读路径**(`ListByPersona` / `List` / `ListScope` / `ListProject`)现在只回 **`status='active'`** 的行 ⇒ 被软合并(`'merged'`)与被归档(`'archived'`)的记忆**不再被召回、不再进上下文、也不再出现在面板 `GET /admin/memories`**(此前它们照样出现 ⇒ 等于「清了也白清」)。🔴 **刻意不过闸的两处**:按 id 的 `Get`(撤销软合并必须先读得到被吸收的行)与 **`GET /admin/memories/reviews`**(审查留痕**本身没有 status 概念**,且它是软删行的查看与撤销入口 —— 加闸等于审计自我抹除)。③ **调度不再饿死(内部行为,对客户端零形状影响)**:整理从「ticker 从进程启动算起、重启十几次就永远走不完 24h」改成**到点即跑 + catch-up**,以 `memory_tidy_runs` 的留痕行为**持久事实**判「上次到底跑过没有」,并把手动真跑端点(B24)做成 panic button。④ **计数**:`writeAuth` 段 19 → **24**、管理路由总数 73 → **78**(`14 + 24 + 40`;按 `routes.go` 逐条核对:经 `writeAuth` 挂载的 **admin** 路由实有 **26** 条,按历史口径减去 §2.4(a) 的 `channels/events` 与 `.../counters` ⇒ **24**)。⚠️ **诚实边界(别当已验证)**:**生产库全程零动作** —— 1191 行记忆与 77 条待定候选**都没有被应用或清理**(等主人拍板,见 §4.15(d));**面板上的真机端到端未跑**(前端操作面在本版登记时尚未落地,并行切片在做);旧候选的 `run_id` 是空串 ⇒ 「**按 run 批量**」找不到它们,要清它们必须走**全部待定**那一档;候选表的 `run_id` 列目前**只在存储包前滚**(`memory.NewStore`),**未**同步进迁移 `0019`。
|
||||
>
|
||||
> **v0.82 是三面增量版(① 已实现(切片 Y1 `215eedf`);② 已实现(切片 Y3 `4213b26`);③ 形状已定、代码在树(切片 Y4 `e0a6bca` + 组合根挂点);**纯增量、无破坏性变更**)**:① **`tool_execution.end` 的 `data` 新增可选 `resultSummary`(string)** —— 工具卡从此能在**实时**显示「这次调用拿到了什么」,不必等事后翻回看面。它修的是「实时只看到工具名与状态、结果要事后才知道」。🔴 **缺席语义(安卓端按此编程)**:**键在场 ⇒ 渲染结果区;键缺席 ⇒ 只显示工具名与状态** —— **内容与回看面 `toolCalls[].resultSummary` 同源同口径**(同一份**已脱敏**文本 `trace.RedactText`:凭据形状清洗 + 截断)、**同一个上限 `≤500` rune**(超长按 rune 截断、末位 `…`);**空值 ⇒ 整键缺席,绝不用空串顶位**(空串会让客户端渲染出一个空的结果区)。**只有「真的没有结果」才缺席**:调用成功但结果为空(nil / 空串)、或错误文本本身为空;`tool_execution.start` / `.update` **不带**该键。⚠️ **失败也带**(本版口径):调用失败 / 取消 / 超时的 `.end` 帧带的是**该次错误文本的脱敏渲染** —— 与回看面(那里失败调用回的是图上的 `error` 摘要)**给同一份说法**,客户端不必为「实时」与「回看」写两套判据。详见 **§3.4.2**。② **自排的成本可见面**(切片 Y3,design/12 §N C.5/C.6)—— `GET /api/v1/admin/backthink` 新增**可选** `?trigger=` **服务端筛选**(取值域 = **闭集**:三个内建标签 + 本服务订阅的事件主题,真源 `backthink.TriggerFilterValues()`;值**未知或为空** ⇒ **`400 invalid_trigger`**,**绝不静默忽略** —— 静默忽略会让面板在显示全部的同时声称「正在筛选」;合法值**下推 SQL**,因此 `limit` 数的是**匹配**条数);新增 1 条 `writeAuth` 只读端点 **`GET /api/v1/admin/backthink/self-wake`**(§2.2 B19 / §4.10(e),**三态** `available`/`running`/`reason` + `gate` 快照 + `configFile`)。⚠️ **`trigger` 的「显示口径」仍是开放的**(客户端按字面值显示、不做闭集校验)—— **筛选白名单**与**显示取值域**是两件事,别混(见 §4.10(d))。③ **`browser` 插件管理面板(B4)**(切片 Y4,design/28 §8)—— `GET /api/v1/admin/panels` 的面板目录新增 `browser` / `settings`(「浏览器与截图」,4 个区块:配置表单 + 状态 / 指纹 / 截图三张只读表),该插件声明**六个动作**(3 读 3 写,见 §4.14(d));**不开任何新路由**(走既有 A14 通用动作分发),因此 §2.0 计数**只**因 ② 的 self-wake 端点 +1。**模型面**(非客户端契约面)另有一条:`browser` 工具的 `screenshot` 返回值新增 **`turnAttachment`**(闭集 `queued` / `no-session` / `outbox-full` / `disabled`)。**④ 本版把 §4.10(d) 一句已成假话的口径改正**:`request_think` **已接线**(`cmd/cyrene/wire_services.go` 的 `wireSelfWakeTool`;启动日志 `self wake tool registered tool=request_think`)⇒ `trigger="self_wake"` 与 4 条 `backthink.self_wake.*` 审计动词**在生产里会真的出现**。**⑤ 计数**:`writeAuth` 段 18 → **19**、管理路由总数 72 → **73**(`14 + 19 + 40`)。⚠️ **登记时的工作树状态(如实)**:③ 的**组合根两个挂点**(`cmd/cyrene/wire_frontend.go` 的 `wireBrowserPanel(hub, a, a.log)`、`cmd/cyrene/wire_runtime.go` 的 `TransformContext: a.browserShotTransform(visionResolver),`)与 ① 的**失败也带摘要**(`internal/runtime/loop/tool_frame_summary.go`)在本版登记时**仍在工作树、未提交** ⇒ 提交前,跑着的后端里**没有**这些行为;提交后请按 `git show` 逐字复核。
|
||||
@@ -1240,7 +1242,7 @@
|
||||
| 动作名 | 语义 | 面 | 请求体 | 成功响应 `result` |
|
||||
|---|---|---|---|---|
|
||||
| `plugin.listProviders` | 列出各条 provider 配置 | read(table `source`) | `{}` | `{"rows":[{"provider":"searxng","state":"ok\|not_configured\|disabled\|unknown","enabled":true}]}`(**凭据/地址不回**) |
|
||||
| `plugin.providers` | 下拉候选:本期**全部已登记**的 provider 名 | read(字段 `optionsFrom:"plugin:providers"`) | `{}` | `{"options":["aliyun_iqs","baidu_qianfan","bocha","searxng","volcengine","zhipu"]}`(稳定排序,**含尚未配置的家**) |
|
||||
| `plugin.providers` | 下拉候选:本期**全部已登记**的 provider(**带显示名**) | read(字段 `optionsFrom:"plugin:providers"`) | `{}` | `{"options":[{"value":"zhipu","label":"智谱 BigModel(zhipu)"},…]}`(稳定排序,**含尚未配置的家**)。🆕 **v0.84 形状变更(对象数组)**:此前是**裸字符串数组**(`{"options":["zhipu",…]}`)。🔴 **两条硬口径**:① **`label` 仅供显示,`value` 才是落盘值** —— 把 `label` 写回 `provider` 字段会把配置文件写坏(提交给 `plugin.saveProvider` 的必须是 `value`);② **前端解码器本就兼容三种形状**(裸字符串 / `{value,label}` / `{id}`)⇒ 仍返回裸字符串的其他插件与老声明**不受影响**(零破坏性)。前端「候选开关」写回的是 `value`;表格单元格按 `value→label` 索引显示、查不到回落显示原值 |
|
||||
| `plugin.saveProvider` | 新增/修改一条(按 `provider` **upsert**);**同一次提交可带两个文件级字段** `primary` / `fallback`(主 provider 与降级链,**缺位 = 不改动**) | write(form `submit`) | `{"values":{"provider":"bocha","apiKey":"…","baseUrl":"https://…","enabled":true,"primary":"bocha","fallback":["searxng"]}}` | `{"saved":true,"provider":"bocha","created":true,"enabled":true,"primary":"bocha","fallback":["searxng"],"hotReload":{"applied":true,"registered":true}}`(`primary` / `fallback` 是**落盘后**的取值,没给也如实回显;`hotReload` 见下) |
|
||||
| `plugin.testProvider` | 测试连通(**真发一次最小检索**) | write(table `rowActions`) | `{"row":{"provider":"bocha"}}`(亦可给 `{"values":{…}}` 或顶层 `provider`) | `{"ok":true,"provider":"bocha","count":1,"latencyMs":123}`;**没通 = 非 2xx**(见错误表),**不在 200 里回 `ok:false`** |
|
||||
| `plugin.reauthProvider` | 重配凭据:把该条带回表单 | write(table `rowActions`) | `{"row":{"provider":"bocha"}}` | `{"values":{"provider":"bocha","apiKey":"****cdef","baseUrl":"https://api.bocha.cn","enabled":true,"primary":"bocha","fallback":["searxng"]}}`(**`apiKey` 只回掩码**;前端对 secret 字段一律不回填输入框,**空 = 不改动**)。⚠️ **v0.80 起 `values` 另带两个文件级字段** `primary`(字符串)/ `fallback`(字符串数组)—— **不带它们**的话,面板「清空降级链」在客户端三态写回里会落成「缺位 = 不改动」(**清不掉**) |
|
||||
@@ -1343,7 +1345,37 @@
|
||||
|
||||
|
||||
|
||||
> **`.env` vs 面板文件**:面板「LLM 模型」页保存写 `<DATA_DIR>/models.json`(默认 `./data/models.json`);「渠道管理」页写 `<DATA_DIR>/channels.json`。**只要文件存在且有效,运行时优先用它**,`.env` 只作兜底/播种层。`.env.example` 与实现同步(键名逐字一致、值占位符)。
|
||||
### 4.16 助手文本的段落标签约束(**v0.84 新增,产出侧硬约束**)
|
||||
|
||||
**约束(一句话)**:助手文本在**落库、对外读接口、IM 镜像**里**不得出现未配对的段落标签** —— 不许有落单的 `<p …>` 或 `</p>`。语义上:**一个 `<p>` = 一段,段落不嵌套**。
|
||||
|
||||
**为什么写进契约**(这曾是真实纠纷):安卓端从 `GET /api/v1/sessions/web/messages` 读到过一条 `content` 形如
|
||||
|
||||
```
|
||||
<p><action>满意地点点头</action></p>
|
||||
<p>真乖♪ 这可是今天最让人家放心的一句。</p>
|
||||
<p><p>那现在——想让人家陪你看会儿晚霞,还是安静坐着发会儿呆?</p>
|
||||
```
|
||||
|
||||
他们的解析契约 `P_BLOCK_RE = <p(\s[^>]*)?>([\s\S]*?)</p>` 是**非贪婪**的 ⇒ 第三段必然匹配成「外层 `<p>` 开、内容 = `<p>正文`、`</p>` 收」⇒ **用户直接看到字面的 `<p>`**。这不是他们解析器的口味问题:**任何按该契约定实现的消费方(Web 面板 / IM 桥 / 第三方)都会踩**。
|
||||
|
||||
**实测根因(两半都在产出侧,已修 `8051906`)**:
|
||||
|
||||
1. 规整器**原样放过**该形状(分块正则非贪婪 ⇒ `<p><p>X</p>` 被当成「一个已完整包裹的 `<p>` 块」逐字保留;更糟的是旧的覆盖检查用**同一非贪婪正则**,护栏本身是盲的);
|
||||
2. 规整器还会**亲手制造**它:段首 `<p>` 未闭合(模型末段漏 `</p>`)时**无条件再套一层** —— 实证:模型吐 `<p>那现在…?`(无闭标签)经旧代码规整后与上报串**逐字节相同**;
|
||||
3. 顺带修掉一个**幂等漏洞**:落单 `</p>` 旧行为 ⇒ `<p>正文。</p></p>`,再跑一次又变 ⇒ 越跑越多。
|
||||
|
||||
**修后的处置口径(产出侧,逐条有测试)**:`<p><p>X</p>` ⇒ `<p>X</p>`;`<p>X`(漏闭)⇒ 补 `</p>`(**补闭不补开**);`<p>正文<p>` ⇒ `<p>正文</p>`(合并不吞字);`<p>A</p><p>` ⇒ `<p>A</p>`(丢空开标签、不造空气泡);`<p></p>` ⇒ 整对丢;落单 `</p>` ⇒ 丢标签、**正文不动**。
|
||||
|
||||
**🔴 客户端要做 / 不用做的**:
|
||||
|
||||
- **不用做**:不必为这个畸形写特例解析器(产出侧已保证不再产出)。
|
||||
- **仍要做**:**保留**你现有的「剥落单标签」容错 —— ① **历史行不回填**(库里已经有畸形的行);② 产出链**不止一条**(渠道镜像 / 主动推送 / 后台思考各有包装点),不能假设全都干净。
|
||||
- **护栏(不许退化)**:`1 < 2`、`a<b`、`<p2>`、`<p`(无 `>`)、代码围栏内的 `<p>`、`<action>` 块内的 `<p>`、自闭合 `<p/>` —— 这些**都不是**段落标签,一律原样保留(产出侧与消费侧**同一条口径**)。
|
||||
|
||||
**一个保守处置(待设计裁决,生产库 0 例)**:`<p>A\n\n<p>B</p>`(未闭合段落之间夹正文)产出侧选择**合并** ⇒ `<p>A\n\nB</p>`,**不**做「插入式隐式收尾」(那要猜作者意图)。客户端不必为此适配。
|
||||
|
||||
## 5. env 与模型配置(与契约相关)(默认 `./data/models.json`);「渠道管理」页写 `<DATA_DIR>/channels.json`。**只要文件存在且有效,运行时优先用它**,`.env` 只作兜底/播种层。`.env.example` 与实现同步(键名逐字一致、值占位符)。
|
||||
|
||||
| 键 | 默认 | 与契约的关系 |
|
||||
|---|---|---|
|
||||
@@ -1414,7 +1446,21 @@
|
||||
> 只保留最近若干版(**v0.60 起**);更早的全部历史见归档 `Docs/archive/api-client.v0.65.md` §5(v0.28 → v0.59)。
|
||||
> 每版一句话 + 三档标注。**三档定义见 [§0.4](#04-三档标注惯例)。**
|
||||
|
||||
### v0.83(当前契约版本)
|
||||
### v0.84(当前契约版本)
|
||||
|
||||
**「显示名 + 段落标签硬约束」版 —— 一处形状变更(插件动作响应)+ 一处新增产出侧硬约束 + 一条模型面登记**(依据:主人报障「下拉里全给英文名,你甚至不愿意带个括号把中文名写上去」;安卓端登记 `<p><p>正文</p>` 畸形;`design/28 §1 M5 / §8 B5` 的浏览器降级档。切片:显示名 `c46053e`、段落修复 `8051906`、provider 配置面去 env 化 `bc1dee3`、搜索 linkless 修复 `2c56bc9`。)
|
||||
|
||||
- **① 形状变更:`plugin.providers` 候选从裸字符串数组 → 对象数组 `{value,label}`**。见 **§4.14(c)** 与 §2.1 A14。根因**不是**漏写文案,而是**整条链路没有「显示名」的位置**(字段声明只有 `optionsFrom`,动作回的就是 `KnownNames()` 的纯 id 数组)。中文名逐字:`SearXNG 本地兜底(searxng)` / `智谱 BigModel(zhipu)` / `阿里云 IQS 信息查询(aliyun_iqs)` / `博查 Bocha(bocha)` / `火山引擎·豆包搜索(volcengine)` / `百度千帆 AI 搜索(baidu_qianfan)`。🔴 **`label` 仅供显示、`value` 才是落盘值**;前端解码器兼容三种形状 ⇒ 其他插件零影响;表格按 `value→label` 索引显示、查不到回落原值。
|
||||
- **② 新增产出侧硬约束:助手文本不得出现未配对的段落标签**(落单 `<p …>` / `</p>`)。见 **§4.16**。修的是安卓登记的 `<p><p>正文</p>`;**两半根因都在产出侧**(规整器原样放过 + 在「末段漏 `</p>`」时亲手制造),另修一个幂等漏洞。**历史行不回填**、消费方**仍应保留**容错。
|
||||
- **③ 模型面登记(非客户端契约面)**:`web-fetch` 的浏览器渲染降级档已接线,返回体用 `fetchedBy`(`direct` / `browser`)**如实标注**正文实际来自哪条路;两条档的失败各自留痕,**绝不静默替换**,被 SSRF 拒绝的目标**不换路**。
|
||||
- **④ provider 配置面「去 env 化」(对客户端零形状影响,登记供跨端对照)**:新增 provider 不再需要新的 `.env` 键 —— 面板文件 `$DATA_DIR/config/plugins/web-search.json` **是权威**,`.env` 只在文件缺失/为空时**播种**(文件一旦存在,「文件里没有的家」**不从 env 复活** —— 这是既有回归用例钉住的口径,本次未改);各家「没配 baseUrl 就回落代码默认值」的默认值表移进接入位表(`search.Descriptor.DefaultBaseURL`),**逐字未变**。
|
||||
- **行为变更**:**有一处(且是"变真")**:① 让「文件里没有的家不从 env 复活」这条既有口径在**新家**上也成立(此前新家根本进不来);② 段落标签约束让产出**不再畸形**(对不产畸形的部署零影响)。
|
||||
- **破坏性**:**无**(`plugin.providers` 只改**候选**形状且前端三形状兼容;无键被删、无端点被删、无既有语义被改)。
|
||||
- **计数**:**无新端点** ⇒ §2.0 权限矩阵维持 **14 + 24 + 40 = 78**(§2.2 B1–B24)。
|
||||
- **验证证据(本版实测)**:`go build ./...` + 各包 `vet` 绿;相关包测试全绿;三处变异由主会话**亲自**复现打红(把 `option.value` 换成 `option.label` ⇒ 渲染测试红,输出正是会写坏配置的 `"bocha, 智谱 BigModel(zhipu)"`;摘掉配对修复接线 ⇒ 段落用例红;把「文件里的 key」忽略 ⇒ 4 条 provider 投影用例红)。
|
||||
- ⚠️ **诚实边界**:① **`web-search` 真机工具路径在登记时仍有一处未部署的修复**(详见 v0.84 横幅与 §7.2)—— 已推库、**未 build/restart**;② 显示名的**真机浏览器点击**未跑(项目无 jsdom,证据止于渲染层)—— **且 `internal/webui/dist` 是 `go:embed` 进二进制的,前端改动必须重新 `build` 才生效**(子代理曾误称"纯前端改动不需要重启",已纠正);③ **`viewer` 角色看不到 form 区块** ⇒ 表格对 viewer 仍显示裸 id(未做);④ 腾讯云元宝 / 秘塔两家的适配**尚未实现**(文档已逐页落盘)。
|
||||
|
||||
### v0.83(上一版)
|
||||
|
||||
**记忆整理「应用面」—— 五条 `writeAuth` 新端点 + 读侧 status 闸(行为修复)**(切片 TIDY-1 `454ddb0` + `9126d65` + `f847769`;依据:`design/23` §7/§8/§10/§11;主人实测口径「候选 77 条全 pending、两天一条没应用」+「重复无效记忆都一千多条了」。)
|
||||
|
||||
|
||||
Reference in new issue
Block a user