@sema-agent/server 3.15.0 → 3.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/plugins/web-search.d.ts +29 -0
- package/dist/plugins/web-search.js +29 -0
- package/dist/session-sync.js +29 -5
- package/package.json +1 -1
|
@@ -12,6 +12,35 @@
|
|
|
12
12
|
* and re-enforces the `allowed_domains`/`blocked_domains` FLOOR on them, so honoring `opts` here is an optimization,
|
|
13
13
|
* not a correctness requirement (a backend MAY ignore it). The API key comes from deployment env — it never enters
|
|
14
14
|
* the model prompt or the tool args. `effect:"read"` (idempotent) is core's concern; this is just the transport.
|
|
15
|
+
*
|
|
16
|
+
* ── 立案:装配层四条缺口([2176] 我方认领,2026-08-01 调研,**尚未实施**)────────────────────
|
|
17
|
+
*
|
|
18
|
+
* ① **`opts` 只有 tavily 腿在消费**(`brave`/`searxng` 的 switch 分支不传 `opts`)。
|
|
19
|
+
* 定性:**优化缺失,不是正确性缺口** —— 上面那句「core 再执行一次 FLOOR」经亲验属实
|
|
20
|
+
* (core `dist/tools/web.js` 的 `webSearchResultAllowed(url, allowed, blocked)`,按 hostname
|
|
21
|
+
* 逐条过滤 blocked/allowed)。所以模型请求的域限制**不会**被静默丢弃。
|
|
22
|
+
* 但代价真实:后端搜回一堆注定被 core 丢掉的结果 ⇒ 白花配额、白等延迟,极端情况下
|
|
23
|
+
* 「限域搜索」返回 0 条(拿回来的 N 条全不在 allowed 里)而后端其实能做原生过滤。
|
|
24
|
+
* ⚠️ 判据留痕:我第一轮把这条判成了「约束被静默丢弃」的安全缺口,是**亲读 core 结果侧代码**
|
|
25
|
+
* 才推翻的。「别处已经处理了」这种声明必须验证 —— 这次它是真的,但真假只能靠读。
|
|
26
|
+
*
|
|
27
|
+
* ② **searxng 腿是自铸的第二真源**。core 2.10 起已导出 `createSearxngSearchBackend`
|
|
28
|
+
* (+`SearxngBackendOptions`),而且比本文件的实现多三样:`allowedDomains` 拼 `site:` 原生下推、
|
|
29
|
+
* `extraParams`(实例特定的 `engines=`/`language=` 等)、**自带 timeout**
|
|
30
|
+
* (`AbortSignal.any([signal, timeout])`;本文件的 searxng 腿只吃外部 signal)。
|
|
31
|
+
* 我在黑板 [2190] 已公开表态「按 core 的接、不再自铸第二真源」—— 这条是待兑现的债。
|
|
32
|
+
* 换的时候要核对的等价点:本文件的 `normalize()` 统一形状 + `max` 截断 +
|
|
33
|
+
* `setWebSearchBadPayloadObserver` 观测器,core 的 adapter 都没有,得在外层补回来。
|
|
34
|
+
*
|
|
35
|
+
* ③ **四级优先级语义未定**(env / config-center / per-scenario / per-request 谁压谁)。
|
|
36
|
+
* 🔴 三问里「谁被伤」这条决定了默认值:一个**只配了模型 key** 的既有部署,若新语义让某一级
|
|
37
|
+
* 能自行打开搜索,它就在升级后**凭空长出一条出网工具** —— 那是安全姿态变更,不是特性。
|
|
38
|
+
* ⇒ 语义定稿前,任何新的开启通道**默认 OFF**;开启必须是部署方的显式动作。
|
|
39
|
+
*
|
|
40
|
+
* ④ **探活 verb 缺席**。core 2.10 起导出 `probeSearchBackend(search, {timeoutMs}) →
|
|
41
|
+
* {ok:true,results:n} | {ok:false,error}`,正好填这条:部署方现在只能靠「跑一个真任务」
|
|
42
|
+
* 验证搜索配对不对。挂哪儿(boot 期一次性 warn / `/health` 子字段 / 显式端点)未定 ——
|
|
43
|
+
* 注意 boot 期探活会给每次启动加一次出网,多租/离线部署要能关。
|
|
15
44
|
*/
|
|
16
45
|
/** Search providers this backend speaks. Absent `WEB_SEARCH_PROVIDER` ⇒ no backend ⇒ WebSearch is not assembled. */
|
|
17
46
|
export type WebSearchProvider = "brave" | "tavily" | "searxng";
|
|
@@ -12,6 +12,35 @@
|
|
|
12
12
|
* and re-enforces the `allowed_domains`/`blocked_domains` FLOOR on them, so honoring `opts` here is an optimization,
|
|
13
13
|
* not a correctness requirement (a backend MAY ignore it). The API key comes from deployment env — it never enters
|
|
14
14
|
* the model prompt or the tool args. `effect:"read"` (idempotent) is core's concern; this is just the transport.
|
|
15
|
+
*
|
|
16
|
+
* ── 立案:装配层四条缺口([2176] 我方认领,2026-08-01 调研,**尚未实施**)────────────────────
|
|
17
|
+
*
|
|
18
|
+
* ① **`opts` 只有 tavily 腿在消费**(`brave`/`searxng` 的 switch 分支不传 `opts`)。
|
|
19
|
+
* 定性:**优化缺失,不是正确性缺口** —— 上面那句「core 再执行一次 FLOOR」经亲验属实
|
|
20
|
+
* (core `dist/tools/web.js` 的 `webSearchResultAllowed(url, allowed, blocked)`,按 hostname
|
|
21
|
+
* 逐条过滤 blocked/allowed)。所以模型请求的域限制**不会**被静默丢弃。
|
|
22
|
+
* 但代价真实:后端搜回一堆注定被 core 丢掉的结果 ⇒ 白花配额、白等延迟,极端情况下
|
|
23
|
+
* 「限域搜索」返回 0 条(拿回来的 N 条全不在 allowed 里)而后端其实能做原生过滤。
|
|
24
|
+
* ⚠️ 判据留痕:我第一轮把这条判成了「约束被静默丢弃」的安全缺口,是**亲读 core 结果侧代码**
|
|
25
|
+
* 才推翻的。「别处已经处理了」这种声明必须验证 —— 这次它是真的,但真假只能靠读。
|
|
26
|
+
*
|
|
27
|
+
* ② **searxng 腿是自铸的第二真源**。core 2.10 起已导出 `createSearxngSearchBackend`
|
|
28
|
+
* (+`SearxngBackendOptions`),而且比本文件的实现多三样:`allowedDomains` 拼 `site:` 原生下推、
|
|
29
|
+
* `extraParams`(实例特定的 `engines=`/`language=` 等)、**自带 timeout**
|
|
30
|
+
* (`AbortSignal.any([signal, timeout])`;本文件的 searxng 腿只吃外部 signal)。
|
|
31
|
+
* 我在黑板 [2190] 已公开表态「按 core 的接、不再自铸第二真源」—— 这条是待兑现的债。
|
|
32
|
+
* 换的时候要核对的等价点:本文件的 `normalize()` 统一形状 + `max` 截断 +
|
|
33
|
+
* `setWebSearchBadPayloadObserver` 观测器,core 的 adapter 都没有,得在外层补回来。
|
|
34
|
+
*
|
|
35
|
+
* ③ **四级优先级语义未定**(env / config-center / per-scenario / per-request 谁压谁)。
|
|
36
|
+
* 🔴 三问里「谁被伤」这条决定了默认值:一个**只配了模型 key** 的既有部署,若新语义让某一级
|
|
37
|
+
* 能自行打开搜索,它就在升级后**凭空长出一条出网工具** —— 那是安全姿态变更,不是特性。
|
|
38
|
+
* ⇒ 语义定稿前,任何新的开启通道**默认 OFF**;开启必须是部署方的显式动作。
|
|
39
|
+
*
|
|
40
|
+
* ④ **探活 verb 缺席**。core 2.10 起导出 `probeSearchBackend(search, {timeoutMs}) →
|
|
41
|
+
* {ok:true,results:n} | {ok:false,error}`,正好填这条:部署方现在只能靠「跑一个真任务」
|
|
42
|
+
* 验证搜索配对不对。挂哪儿(boot 期一次性 warn / `/health` 子字段 / 显式端点)未定 ——
|
|
43
|
+
* 注意 boot 期探活会给每次启动加一次出网,多租/离线部署要能关。
|
|
15
44
|
*/
|
|
16
45
|
const DEFAULT_MAX_RESULTS = 10;
|
|
17
46
|
const DEFAULT_TIMEOUT_MS = 10_000;
|
package/dist/session-sync.js
CHANGED
|
@@ -249,12 +249,36 @@ export async function importSession(bundle, getBlob, dstBackend, importingPrinci
|
|
|
249
249
|
await fsWipe.deleteBySession(sessionId);
|
|
250
250
|
else
|
|
251
251
|
await fsWipe.reap(sessionId, []);
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
252
|
+
// 🔴 [2195] 同族(2026-08-01):这两条此前是「有 seam 就删,没有就**静默跳过**」——而本段开头
|
|
253
|
+
// 逐字论证了为什么必须删(「a MIXED state is worse than lost history:dangling anchors resolve onto
|
|
254
|
+
// purged entries, an abandoned branch's policy rows keep gating」)。论证了坏状态不可接受,却在能力
|
|
255
|
+
// 缺席时放行了它自己点名的那个坏状态,且**一声不响**。与 session owner 门那条同族:
|
|
256
|
+
// **能力探测的失败方向决定整条保证的失败方向**,保护型能力缺席必须 fail-closed。
|
|
257
|
+
//
|
|
258
|
+
// 改成 fail-loud:wipe 不了就不继续(此时还**没有**任何写入落地 —— 本段在 §8 的 ①③④ 之前,
|
|
259
|
+
// 所以抛在这里是干净的中止,不是半写状态)。in-tree 每个 store 自 core 1.423 起都带这个 seam
|
|
260
|
+
// ⇒ 我们自己的部署零影响;受影响的只有 seam 之前的第三方 store,而它们此前拿到的是坏数据。
|
|
261
|
+
// 🔴 [2195] 同族(2026-08-01):这两条此前都是「有 seam 就删,没有就**静默跳过**」——而本段开头
|
|
262
|
+
// 逐字论证了为什么必须删(「a MIXED state is worse than lost history:dangling anchors resolve onto
|
|
263
|
+
// purged entries, an abandoned branch's policy rows keep gating」)。论证了坏状态不可接受,却在能力
|
|
264
|
+
// 缺席时放行了它自己点名的那个坏状态,且一声不响。
|
|
265
|
+
//
|
|
266
|
+
// 但两条的**类型事实不同**(旧码用同一个 `as { deleteBySession?: … }` 把两者抹平了,那个 `as` 正是
|
|
267
|
+
// 遮蔽物):
|
|
268
|
+
// · `ResumeAnchorStore.deleteBySession` —— **必填**。类型系统已经排除了「没有」的可能,那个
|
|
269
|
+
// feature-detect 是**为一个不可达场景**写的分支;注释里「for third-party stores that predate the
|
|
270
|
+
// seam」的说法与类型不符(这样的 store 根本进不来)。⇒ 删掉探测,直接调用。真有 JS 层绕过来的
|
|
271
|
+
// 残缺实现,直接调用抛 TypeError 也是 fail-loud,不必自己写。
|
|
272
|
+
// · `SessionPolicyStore.deleteBySession` —— **可选**(且返回 `Promise<void>`,与 anchor 的
|
|
273
|
+
// `Promise<number>` 不同;这个差异也是被那个 `as` 抹掉的)。⇒ 探测保留,但缺席时 fail-loud。
|
|
274
|
+
//
|
|
275
|
+
// 抛在这里是干净的中止:本段在 §8 的 ①③④ 之前,还没有任何写入落地。
|
|
276
|
+
await dstBackend.resumeAnchor().deleteBySession(sessionId);
|
|
255
277
|
const policyWipe = dstBackend.sessionPolicy();
|
|
256
|
-
if (typeof policyWipe.deleteBySession
|
|
257
|
-
|
|
278
|
+
if (typeof policyWipe.deleteBySession !== "function") {
|
|
279
|
+
throw new Error(`overwrite-dst cannot proceed: this deployment's session-policy store has no deleteBySession purge seam, so the destination's policy rows for this session cannot be wiped. Completing the import would leave a MIXED state (the source's conversation plus the destination's stale policy rows, which keep gating), which is worse than the history loss you consented to. Upgrade to a policy store carrying deleteBySession (every in-tree store has it since core 1.423), or re-run without resolution:"overwrite-dst".`);
|
|
280
|
+
}
|
|
281
|
+
await policyWipe.deleteBySession(sessionId);
|
|
258
282
|
}
|
|
259
283
|
// ── §8 atomic order ─────────────────────────────────────────────────────────────────────────────────────────
|
|
260
284
|
// ① snapshots — content-addressed blobs + manifest, BEFORE session_meta. Feature-detect importManifest: ALL backends
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "3.15.
|
|
3
|
+
"version": "3.15.1",
|
|
4
4
|
"description": "Sema Server — the server/API implementation layer for Sema, wiring core, registry, model providers, and cloud agent execution. Built on @sema-agent/core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|