@sema-agent/server 7.81.0 → 7.82.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.
Files changed (40) hide show
  1. package/USAGE.md +44 -14
  2. package/dist/boot/memory-consolidation.d.ts +38 -0
  3. package/dist/boot/memory-consolidation.js +14 -0
  4. package/dist/boot/runner-deps.d.ts +11 -0
  5. package/dist/boot/runner-deps.js +15 -0
  6. package/dist/boot/stage-06-runners.js +13 -8
  7. package/dist/boot/stage-07-capability-layer.d.ts +1 -0
  8. package/dist/boot/stage-07-capability-layer.js +1 -1
  9. package/dist/boot/stage-08-reapers.d.ts +1 -0
  10. package/dist/boot/stage-09-leader.d.ts +1 -0
  11. package/dist/boot/stage-10-http-server.d.ts +1 -0
  12. package/dist/boot/stage-10-http-server.js +2 -1
  13. package/dist/config-catalog.js +3 -2
  14. package/dist/config-types.d.ts +26 -0
  15. package/dist/config.js +9 -1
  16. package/dist/http/routes/capabilities.js +2 -0
  17. package/dist/http/server.d.ts +8 -0
  18. package/dist/observability/metrics.js +1 -0
  19. package/dist/plugins/posix-shell-fs.d.ts +2 -1
  20. package/dist/plugins/posix-shell-fs.js +4 -1
  21. package/dist/plugins/remote-env-adb.d.ts +67 -4
  22. package/dist/plugins/remote-env-adb.js +30 -15
  23. package/dist/plugins/remote-env-e2b.d.ts +8 -1
  24. package/dist/plugins/remote-env-e2b.js +4 -1
  25. package/dist/plugins/remote-env-host.d.ts +15 -1
  26. package/dist/plugins/remote-env-host.js +37 -1
  27. package/dist/plugins/remote-env-k8s.d.ts +5 -1
  28. package/dist/plugins/remote-env-k8s.js +3 -0
  29. package/dist/plugins/remote-env-local-docker.d.ts +5 -1
  30. package/dist/plugins/remote-env-local-docker.js +3 -0
  31. package/dist/plugins/remote-env-ssh.d.ts +5 -1
  32. package/dist/plugins/remote-env-ssh.js +3 -0
  33. package/dist/plugins/remote-shell.d.ts +74 -1
  34. package/dist/plugins/remote-shell.js +35 -0
  35. package/dist/plugins/web-search.d.ts +50 -2
  36. package/dist/plugins/web-search.js +9 -2
  37. package/dist/trace/core-keyset-guard.d.ts +6 -1
  38. package/dist/trace/project.d.ts +18 -0
  39. package/dist/trace/project.js +11 -0
  40. package/package.json +3 -3
@@ -52,8 +52,56 @@
52
52
  * 验证搜索配对不对。挂哪儿(boot 期一次性 warn / `/health` 子字段 / 显式端点)未定 ——
53
53
  * 注意 boot 期探活会给每次启动加一次出网,多租/离线部署要能关。
54
54
  */
55
- /** Search providers this backend speaks. Absent `WEB_SEARCH_PROVIDER` ⇒ no backend ⇒ WebSearch is not assembled. */
56
- export type WebSearchProvider = "brave" | "tavily" | "searxng";
55
+ /**
56
+ * Search providers this backend speaks —— **词表的唯一属主**(运行期与类型同一份)。
57
+ * Absent `WEB_SEARCH_PROVIDER` ⇒ no backend ⇒ WebSearch is not assembled.
58
+ *
59
+ * 🔴 **为什么是常量元组而不是裸 union**(车GW 对抗复审 F1[medium],2026-09-17):改前这张表在仓里有**四份**
60
+ * —— 类型一份 + 两只解析器各一条 `provider !== "brave" && …` 后置链 + `config-catalog` 的
61
+ * `enumValues: [...]` 字面量(那个字段是 `readonly string[]`,与本类型零类型联系)。加一只后端时 tsc
62
+ * **只红** `createWebSearchBackend` 的 switch:守卫链把 provider 收窄成旧三词,而旧三词是新 union 的
63
+ * 子集 ⇒ 赋值合法 ⇒ 改完 switch 全绿发版,`WEB_SEARCH_PROVIDER=<新词>` 却被判 undefined、能力位
64
+ * (`projectWebSearchCapability`)诚实报 `"none"`,运维以为自己配上了。收成一只元组之后:类型从它派生、
65
+ * 两只解析器读它、目录行**就用它本人**(身份相等有钉),规则集从四张表降到一张。
66
+ */
67
+ export declare const WEB_SEARCH_PROVIDERS: readonly ["brave", "tavily", "searxng"];
68
+ export type WebSearchProvider = (typeof WEB_SEARCH_PROVIDERS)[number];
69
+ /**
70
+ * S-382:`GET /v1/capabilities` 的 `webSearch` 位 —— **部署默认后端**的闭集自述。
71
+ *
72
+ * ## 病
73
+ * 「这台 worker 的搜索走哪只后端」此前只在 operator 面可知(`GET /v1/config/catalog` 的
74
+ * `WEB_SEARCH_PROVIDER` 行)。消费端(cli doctor / client-core 的能力投影)要答「本部署有没有搜索、
75
+ * 是哪一只」,只能让用户跑一个真任务去撞 —— 而搜索缺席时工具**根本不装配**(`capabilities/scenarios.ts`
76
+ * 的 `assembleCodeTools({ webSearch })`),模型只会说「我没有这个工具」,那句话在 UX 上与「后端配错了」
77
+ * 不可区分。
78
+ *
79
+ * ## 形
80
+ * `{ backend: "brave" | "tavily" | "searxng" | "none" }`。三条纪律逐条写明:
81
+ * ① **词源单点** —— 闭集是 {@link WebSearchProvider} **取型** ∪ `"none"`,而该类型又派生自
82
+ * {@link WEB_SEARCH_PROVIDERS}(全仓**唯一**一张 provider 词表:两只解析器读它、`config-catalog` 的
83
+ * `enumValues` **就用它本人**〔身份相等有钉〕)。加一只后端 = 改那只元组一处,这一位自动跟着长;
84
+ * 没跟上的地方只剩 `createWebSearchBackend` 的穷尽 `switch`,而那一处是**编译红**。
85
+ * ② **只出词,不出内情** —— 端点(SearXNG 实例 URL)、API key、配额一个字都不上这条 wire:本面在
86
+ * service-credential 门之后但**非 operator 专属**,任何拿得到凭据的调用方都读得到它。
87
+ * ③ **广告的是部署默认** —— 每请求的 `body.settings.webSearch`(单用户车道上**压过**部署座,见
88
+ * `capabilities/scenarios.ts` 的 default 场景)**刻意不在这一面回显**:那是请求方自己送进来的东西,
89
+ * 把它回显出去等于让能力面随调用方漂,而消费端正是拿这一位去渲「这台机器有没有搜索」的。
90
+ */
91
+ export interface WebSearchCapability {
92
+ readonly backend: WebSearchProvider | "none";
93
+ }
94
+ /**
95
+ * 部署席 → 消费端窄投影。**唯一**写 `"none"` 的地方(缺席折词的属主),形照 `projectSqlEngineCapability` /
96
+ * `projectWriteProtectionCapability`。
97
+ *
98
+ * 🔴 缺席折 `"none"` **不是**兜底 fail-open:`undefined`(装配没喂席位 / `WEB_SEARCH_PROVIDER` 未设或拼错)
99
+ * 与「本部署没有搜索后端」在**行为上是同一件事** —— `webSearchConfigFromEnv` 对这两种输入都返回
100
+ * `undefined`,于是 WebSearch 工具都不装配。方向也是安全的那一向:本位只会**少报**能力(说没有、其实
101
+ * 也真没有),不会替一台没配后端的部署点亮一格。「键整个缺席」才是另一回事(= 老 server),那一层由
102
+ * 消费端的探位纪律管,见契约附录 B.1 本行的「缺席何义」。
103
+ */
104
+ export declare function projectWebSearchCapability(provider: WebSearchProvider | undefined): WebSearchCapability;
57
105
  export interface WebSearchBackendConfig {
58
106
  readonly provider: WebSearchProvider;
59
107
  /** API key (brave/tavily). From `WEB_SEARCH_API_KEY` — never reaches the model. */
@@ -1,4 +1,11 @@
1
1
  import { createSearxngSearchBackend } from "@sema-agent/core";
2
+ export const WEB_SEARCH_PROVIDERS = ["brave", "tavily", "searxng"];
3
+ function isWebSearchProvider(word) {
4
+ return WEB_SEARCH_PROVIDERS.includes(word);
5
+ }
6
+ export function projectWebSearchCapability(provider) {
7
+ return provider === undefined ? { backend: "none" } : { backend: provider };
8
+ }
2
9
  const DEFAULT_MAX_RESULTS = 10;
3
10
  const DEFAULT_TIMEOUT_MS = 10_000;
4
11
  const BRAVE_BASE = "https://api.search.brave.com/res/v1/web/search";
@@ -152,7 +159,7 @@ export function shouldProbeWebSearchOnBoot(env = process.env) {
152
159
  }
153
160
  export function webSearchConfigFromEnv(env = process.env) {
154
161
  const provider = env.WEB_SEARCH_PROVIDER?.trim().toLowerCase();
155
- if (provider !== "brave" && provider !== "tavily" && provider !== "searxng")
162
+ if (provider === undefined || !isWebSearchProvider(provider))
156
163
  return undefined;
157
164
  const searxngParams = parseSearxngParams(env.WEB_SEARCH_SEARXNG_PARAMS);
158
165
  const maxRaw = Number(env.WEB_SEARCH_MAX_RESULTS ?? "");
@@ -171,7 +178,7 @@ export function webSearchConfigFromSettings(raw) {
171
178
  return undefined;
172
179
  const s = raw;
173
180
  const provider = typeof s.provider === "string" ? s.provider.trim().toLowerCase() : "";
174
- if (provider !== "brave" && provider !== "tavily" && provider !== "searxng")
181
+ if (!isWebSearchProvider(provider))
175
182
  return undefined;
176
183
  const max = typeof s.maxResults === "number" && Number.isFinite(s.maxResults) && s.maxResults > 0 ? Math.floor(s.maxResults) : undefined;
177
184
  return {
@@ -60,7 +60,7 @@ type MailboxAppendProjected = "from" | "content" | "sentAt" | "hopChain" | "peer
60
60
  type _GuardMailboxAppend = AssertAllKeysHandled<Exclude<keyof MailboxAppendMessage, MailboxAppendProjected>>;
61
61
  type _GuardMailboxAppendReverse = AssertAllKeysHandled<Exclude<MailboxAppendProjected, keyof MailboxAppendMessage>>;
62
62
  type WiringSectionProjected = "schemaVersion" | "leg" | "ask" | "question" | "interaction" | "elicit" | "parkLane" | "session" | "fleet" | "permissionRules" | "modelGate" | "autoMode" | "mcp" | "tools" | "hooks" | "lsp" | "writeProtection";
63
- type WiringSectionExcluded = "governance" | "configFingerprint";
63
+ type WiringSectionExcluded = "governance" | "configFingerprint" | "autoConsolidation";
64
64
  type _GuardWiringSections = AssertAllKeysHandled<Exclude<keyof WiringManifest, WiringSectionProjected | WiringSectionExcluded>>;
65
65
  type _GuardWiringSectionsReverse = AssertAllKeysHandled<Exclude<WiringSectionProjected | WiringSectionExcluded, keyof WiringManifest>>;
66
66
  type WiringSection<K extends keyof WiringManifest> = NonNullable<WiringManifest[K]>;
@@ -103,6 +103,9 @@ type _GuardWiringRulesReverse = AssertAllKeysHandled<Exclude<WiringRulesHandled,
103
103
  type WiringWriteProtectionHandled = "targetView";
104
104
  type _GuardWiringWriteProtection = AssertAllKeysHandled<Exclude<keyof WiringSection<"writeProtection">, WiringWriteProtectionHandled>>;
105
105
  type _GuardWiringWriteProtectionReverse = AssertAllKeysHandled<Exclude<WiringWriteProtectionHandled, keyof WiringSection<"writeProtection">>>;
106
+ type WiringAutoConsolidationHandled = "onRecommendation";
107
+ type _GuardWiringAutoConsolidation = AssertAllKeysHandled<Exclude<keyof WiringSection<"autoConsolidation">, WiringAutoConsolidationHandled>>;
108
+ type _GuardWiringAutoConsolidationReverse = AssertAllKeysHandled<Exclude<WiringAutoConsolidationHandled, keyof WiringSection<"autoConsolidation">>>;
106
109
  type WiringModelGateHandled = "class" | "removed" | "restore";
107
110
  type _GuardWiringModelGate = AssertAllKeysHandled<Exclude<keyof WiringSection<"modelGate">, WiringModelGateHandled>>;
108
111
  type _GuardWiringModelGateReverse = AssertAllKeysHandled<Exclude<WiringModelGateHandled, keyof WiringSection<"modelGate">>>;
@@ -185,6 +188,8 @@ export type CoreKeysetGuards = [
185
188
  _GuardWiringSections,
186
189
  _GuardWiringWriteProtection,
187
190
  _GuardWiringWriteProtectionReverse,
191
+ _GuardWiringAutoConsolidation,
192
+ _GuardWiringAutoConsolidationReverse,
188
193
  _GuardWiringSectionsReverse,
189
194
  _GuardWiringLeg,
190
195
  _GuardWiringLegReverse,
@@ -604,6 +604,14 @@ export declare function workspaceChangedEventData(ev: {
604
604
  * ⚠️ **缺席 = 第三态**:core 的段是 **present-iff 编译出了判官**,`writeProtectedPaths: []` 的部署
605
605
  * 整段缺席。缺席**绝不**折成 `"spelling-only"`(那是「判官在、但只认拼法」,完全不同的一件事),
606
606
  * 也不铸 `writeProtection: {}`。词出闭集同样**不**折进缺席,走 `dropProjectedFace` 留痕(见那里)。
607
+ * · `autoConsolidation`(`{ onRecommendation: true }`;core 7.21.0 [ref],S-362 提货件)—— **裁:operator
608
+ * 受众,租户面剥**,所以它**不在本构造器里**,在 {@link wiringManifestOperatorEventData}。四条判据逐字在
609
+ * `core-keyset-guard.ts` ⑥b 的 `WiringSectionExcluded` 那一行(与 `governance` / `configFingerprint`
610
+ * 同表同处,免得同一条裁定有两个写者)。一句话:它是**出口事实**(武装 = 每个建议任务之后整库记忆自动
611
+ * 外流到整理模型),与 governance 四布尔同族,而不是 `writeProtection` 那种「这条腿手里有什么」的自述;
612
+ * 并且它对调用方**本就不可观测**(整理跑在终端 harvest 之后、fire-and-forget、宿主侧),剥掉它不收走
613
+ * 任何能力 —— 这正是 `writeProtection` 判据①**不成立**的那一格。
614
+ * ⚠️ **缺席 = 未武装**(core present-iff),不折 `false`、不读「未知」。
607
615
  * 未来 core 加一段而它没有 audience 标签时,**先在这里补一条裁定再决定挑不挑键** —— 段级完备性钉
608
616
  * (test/wiring-manifest-projection.test.ts)会在那一刻先把人拦下来 —— ⚠️ **但那条钉是夹具驱动的**:它只看
609
617
  * `deriveWiringManifest(EFFECTIVE_FACTS)` 真铸出来的段,facts 不带的可选段(147③ 的 `autoMode` 就是)它一格
@@ -662,6 +670,16 @@ export declare function wiringManifestEventData(ev: {
662
670
  *
663
671
  * governance **逐键挑**(禁 `{...governance}`):core 往这个段里加第五键时必须由人显式处置,而不是顺着
664
672
  * spread 裸上线 —— 这个段的每一键都是部署治理面,新键的默认待遇必须是「不发」。
673
+ *
674
+ * `autoConsolidation`(core 7.21.0 [ref],S-362)与 governance 同规:租户面剥、本面发(裁定四条判据在
675
+ * `core-keyset-guard.ts` ⑥b `WiringSectionExcluded`)。**present-iff 武装**:
676
+ * · 整段缺席 ⇒ **未武装**,不铸键、不计数(正面事实,不是「未知」,更不是 `{onRecommendation:false}`);
677
+ * · 在场且 `onRecommendation === true` ⇒ 逐字铸出(core 的在场形只有这一个,构造期门已拒掉「武装但跑不起来」);
678
+ * · 在场但读不出那个形 ⇒ `dropProjectedFace` 留痕并整段缺席(与 `writeProtection` / `lsp` / `hooks` 同一条
679
+ * 族规:「在场但读不出 ⇒ 计一次并丢弃」;**不**自造第三态,词表/形的属主在 core)。
680
+ * 🔴 代价如实登记,与 `writeProtection` 那一格逐字同源:wire 上「读不出」与「真未武装」是**同一个形**,
681
+ * 分得开它们的只有 `server.trace.projection-input-malformed` 这只计数 —— 而这一格比那一格更该说清楚,
682
+ * 因为它读错的方向是**把一台正在外流记忆的部署渲染成没在外流**。故本段的读不出**必须**留痕,不许静默。
665
683
  */
666
684
  export declare function wiringManifestOperatorEventData(ev: {
667
685
  manifest?: unknown;
@@ -554,9 +554,20 @@ export function wiringManifestOperatorEventData(ev) {
554
554
  ...(bool(g.memoryAdmission) !== undefined ? { memoryAdmission: g.memoryAdmission } : {}),
555
555
  ...(bool(g.retention) !== undefined ? { retention: g.retention } : {}),
556
556
  };
557
+ const autoConsolidation = (() => {
558
+ if (m.autoConsolidation === undefined)
559
+ return undefined;
560
+ const seg = sec(m.autoConsolidation);
561
+ if (seg === undefined)
562
+ return dropProjectedFace("wiring_manifest.autoConsolidation is not an object");
563
+ if (bool(seg.onRecommendation) !== true)
564
+ return dropProjectedFace("wiring_manifest.autoConsolidation.onRecommendation is not literal true (core's only present form)");
565
+ return { onRecommendation: true };
566
+ })();
557
567
  return {
558
568
  ...tenant,
559
569
  ...(Object.keys(governance).length > 0 ? { governance } : {}),
570
+ ...(autoConsolidation !== undefined ? { autoConsolidation } : {}),
560
571
  ...(str(m.configFingerprint) !== undefined ? { configFingerprint: m.configFingerprint } : {}),
561
572
  };
562
573
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/server",
3
- "version": "7.81.0",
3
+ "version": "7.82.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",
@@ -54,7 +54,7 @@
54
54
  "build:binary:run-local:darwin-arm64": "bun build --compile --target=bun-darwin-arm64 src/run-local.ts --outfile dist/run-local-darwin-arm64"
55
55
  },
56
56
  "dependencies": {
57
- "@sema-agent/core": "7.20.1",
57
+ "@sema-agent/core": "7.21.1",
58
58
  "@sema-agent/settings-schema": "2.1.0",
59
59
  "e2b": "^2.28.0",
60
60
  "libsodium-wrappers": "^0.8.4",
@@ -69,7 +69,7 @@
69
69
  "sharp": "^0.35.3"
70
70
  },
71
71
  "devDependencies": {
72
- "@sema-agent/sdk": "9.5.0",
72
+ "@sema-agent/sdk": "9.6.0",
73
73
  "@types/libsodium-wrappers": "^0.7.14",
74
74
  "@types/node": "22.10.2",
75
75
  "@types/pg": "^8.20.0",