@sema-agent/server 3.17.0 → 3.18.0
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.
|
@@ -24,7 +24,11 @@
|
|
|
24
24
|
* ⚠️ 判据留痕:我第一轮把这条判成了「约束被静默丢弃」的安全缺口,是**亲读 core 结果侧代码**
|
|
25
25
|
* 才推翻的。「别处已经处理了」这种声明必须验证 —— 这次它是真的,但真假只能靠读。
|
|
26
26
|
*
|
|
27
|
-
* ②
|
|
27
|
+
* ② ~~**searxng 腿是自铸的第二真源**~~ —— ✅ **已还(2026-08-01,[2229] 裁定 searxng 为国内可达性
|
|
28
|
+
* 主路线之后)**:本腿改为消费 core 的 `createSearxngSearchBackend`,外层保住 maxResults 截断 /
|
|
29
|
+
* 统一形状 / 坏 payload 观测器三样(各有红先钉 + 变异实测),白得 `site:` 原生下推、`extraParams`、
|
|
30
|
+
* 自带 timeout。以下为原始立案文本,留档:
|
|
31
|
+
* core 2.10 起已导出 `createSearxngSearchBackend`
|
|
28
32
|
* (+`SearxngBackendOptions`),而且比本文件的实现多三样:`allowedDomains` 拼 `site:` 原生下推、
|
|
29
33
|
* `extraParams`(实例特定的 `engines=`/`language=` 等)、**自带 timeout**
|
|
30
34
|
* (`AbortSignal.any([signal, timeout])`;本文件的 searxng 腿只吃外部 signal)。
|
|
@@ -48,6 +52,9 @@ export interface WebSearchBackendConfig {
|
|
|
48
52
|
readonly provider: WebSearchProvider;
|
|
49
53
|
/** API key (brave/tavily). From `WEB_SEARCH_API_KEY` — never reaches the model. */
|
|
50
54
|
readonly apiKey?: string;
|
|
55
|
+
/** SearXNG 实例特定查询参数(`engines=` / `language=` 等)——透传给 core adapter 的 `extraParams`。
|
|
56
|
+
* 一键装 SearXNG 的向导用它把「选了哪些上游引擎」落到引擎侧。仅 searxng 腿消费。 */
|
|
57
|
+
readonly searxngParams?: Record<string, string>;
|
|
51
58
|
/** SearXNG instance base URL (REQUIRED for searxng); for brave/tavily an optional base-URL override (proxy/test). */
|
|
52
59
|
readonly endpoint?: string;
|
|
53
60
|
/** Max results returned to the model (clamped 1..20; default 10). */
|
|
@@ -24,7 +24,11 @@
|
|
|
24
24
|
* ⚠️ 判据留痕:我第一轮把这条判成了「约束被静默丢弃」的安全缺口,是**亲读 core 结果侧代码**
|
|
25
25
|
* 才推翻的。「别处已经处理了」这种声明必须验证 —— 这次它是真的,但真假只能靠读。
|
|
26
26
|
*
|
|
27
|
-
* ②
|
|
27
|
+
* ② ~~**searxng 腿是自铸的第二真源**~~ —— ✅ **已还(2026-08-01,[2229] 裁定 searxng 为国内可达性
|
|
28
|
+
* 主路线之后)**:本腿改为消费 core 的 `createSearxngSearchBackend`,外层保住 maxResults 截断 /
|
|
29
|
+
* 统一形状 / 坏 payload 观测器三样(各有红先钉 + 变异实测),白得 `site:` 原生下推、`extraParams`、
|
|
30
|
+
* 自带 timeout。以下为原始立案文本,留档:
|
|
31
|
+
* core 2.10 起已导出 `createSearxngSearchBackend`
|
|
28
32
|
* (+`SearxngBackendOptions`),而且比本文件的实现多三样:`allowedDomains` 拼 `site:` 原生下推、
|
|
29
33
|
* `extraParams`(实例特定的 `engines=`/`language=` 等)、**自带 timeout**
|
|
30
34
|
* (`AbortSignal.any([signal, timeout])`;本文件的 searxng 腿只吃外部 signal)。
|
|
@@ -42,6 +46,7 @@
|
|
|
42
46
|
* 验证搜索配对不对。挂哪儿(boot 期一次性 warn / `/health` 子字段 / 显式端点)未定 ——
|
|
43
47
|
* 注意 boot 期探活会给每次启动加一次出网,多租/离线部署要能关。
|
|
44
48
|
*/
|
|
49
|
+
import { createSearxngSearchBackend } from "@sema-agent/core";
|
|
45
50
|
const DEFAULT_MAX_RESULTS = 10;
|
|
46
51
|
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
47
52
|
const BRAVE_BASE = "https://api.search.brave.com/res/v1/web/search";
|
|
@@ -130,17 +135,45 @@ async function tavilySearch(fetchImpl, cfg, query, max, signal, opts) {
|
|
|
130
135
|
const data = (await res.json());
|
|
131
136
|
return normalize(data.results, (r) => ({ title: r.title, url: r.url, snippet: r.content }), max, "tavily");
|
|
132
137
|
}
|
|
133
|
-
|
|
138
|
+
/**
|
|
139
|
+
* SearXNG 腿 —— **消费 core 的 `createSearxngSearchBackend`,不再自铸**(#81② 还债;[2190] 表态、
|
|
140
|
+
* [2229] 裁定 searxng 是国内可达性主路线之后该还的那笔)。
|
|
141
|
+
*
|
|
142
|
+
* core 的 adapter 比本文件此前的手写实现多三样,换过来就白得:
|
|
143
|
+
* · `allowedDomains` **原生下推**成 `site:a OR site:b` 前缀(此前本腿完全忽略 opts —— core 工具层
|
|
144
|
+
* 有结果侧 FLOOR 兜底所以不是正确性缺口,但白搜一趟、白花配额,极端情况下限域搜索回 0 条);
|
|
145
|
+
* · `extraParams`(实例特定的 `engines=` / `language=` 等)——一键装 SearXNG 的向导要用;
|
|
146
|
+
* · **自带 timeout**(`AbortSignal.any([signal, timeout])`;此前本腿只吃外部 signal)。
|
|
147
|
+
*
|
|
148
|
+
* ⚠️ core adapter **不管**这三样,必须留在外层(换真源最容易丢的就是它们,已上红先钉):
|
|
149
|
+
* ① `maxResults` 截断 ② 统一形状 `{title,url,snippet}` ③ 坏 payload 观测器。
|
|
150
|
+
*/
|
|
151
|
+
async function searxngSearch(fetchImpl, cfg, query, max, signal, opts) {
|
|
134
152
|
if (!cfg.endpoint)
|
|
135
153
|
throw new Error("WEB_SEARCH_ENDPOINT (the SearXNG instance URL) is required for the searxng provider");
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
154
|
+
const search = createSearxngSearchBackend(cfg.endpoint, {
|
|
155
|
+
fetchImpl,
|
|
156
|
+
...(cfg.searxngParams ? { extraParams: cfg.searxngParams } : {}),
|
|
157
|
+
});
|
|
158
|
+
let rows;
|
|
159
|
+
try {
|
|
160
|
+
rows = await search(query, signal, opts);
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
// core 对「results 不是数组」抛具名错;本腿的既有契约是**不抛给上层、走观测器**(review LOW:
|
|
164
|
+
// 畸形 payload 不该变成裸 TypeError 上抛)。保持既有契约,把它翻译回观测器 + 空结果。
|
|
165
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
166
|
+
if (/no results array/i.test(msg)) {
|
|
167
|
+
try {
|
|
168
|
+
onBadPayload?.("searxng");
|
|
169
|
+
}
|
|
170
|
+
catch { /* observability never breaks search */ }
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
173
|
+
throw e;
|
|
174
|
+
}
|
|
175
|
+
// core 已回 `{title,url,snippet}` 形;仍过一遍 normalize —— ① 截断 ② 形状兜底 ③ 观测器同源。
|
|
176
|
+
return normalize(rows, (r) => ({ title: r.title, url: r.url, snippet: r.snippet }), max, "searxng");
|
|
144
177
|
}
|
|
145
178
|
/**
|
|
146
179
|
* Build the `WebSearchConfig` (a `search` fn + `maxResults`) for `assembleFullBodyTools({ webSearch })`. The API key
|
|
@@ -159,7 +192,7 @@ export function createWebSearchBackend(cfg) {
|
|
|
159
192
|
switch (cfg.provider) {
|
|
160
193
|
case "brave": return await braveSearch(fetchImpl, cfg, q, maxResults, sig);
|
|
161
194
|
case "tavily": return await tavilySearch(fetchImpl, cfg, q, maxResults, sig, opts);
|
|
162
|
-
case "searxng": return await searxngSearch(fetchImpl, cfg, q, maxResults, sig);
|
|
195
|
+
case "searxng": return await searxngSearch(fetchImpl, cfg, q, maxResults, sig, opts);
|
|
163
196
|
}
|
|
164
197
|
}
|
|
165
198
|
finally {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.18.0",
|
|
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",
|