@sema-agent/server 7.91.1 → 7.91.2

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/USAGE.md CHANGED
@@ -1075,7 +1075,7 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
1075
1075
  | `POST /v1/approvals/<sessionId>/decide` `{"decision":"approve"|"deny","reason":"…"}` | 批/否并恢复挂起任务(CAS,重复决议 409);**仅 operator**(非 operator → 403)。5.0.0 起旧轮询腿 `POST /v1/approvals/<id>` 已退役 |
1076
1076
  | `GET /v1/agents/roster` | 后台 agent **名册**(7.29 起,需 durable background-agent store,否则 501 `capability.background_agent_store_required`):调用方自己 scope 的 `a…` 行,新→旧。行只带 `handle`/`name`/`agentType`/`status`/`spawnedAt`/`updatedAt`/`settledAt`(content-free;子代产物正文走 `GET /v1/runs/<id>/subagents/<handle>/output`)。查询:`?limit=`(1..100,默认 20)、`?before=`(上一页的 `nextBefore` 游标)、`?status=`(running\|parked\|completed\|failed\|killed)、`?session=`(按会话树窄化)、`?scope=`(**仅** service-token/单用户形;带 principal 的调用方锁定自己)。回体 `{agents,total,nextBefore?,truncated?}`;`truncated:true` = 租户行数超过名册窗(500),`total` 此时是窗内数。非属主的行**不出现也不计数**(无存在性 oracle) |
1077
1077
  | `GET /v1/capabilities/scenarios/<name>` | 单个场景的只读详情:工具面、提示词概览、**本部署现在跑不跑得动**(见下) |
1078
- | `POST /v1/admin/drain` `{"reason":"…"}` | **停机因由显式声明**(7.35.0+;operator-only —— principal 须在 `OPERATOR_PRINCIPALS` 内,空名单 = 谁都不是 operator ⇒ 恒 403)。编排壳在发 SIGTERM **之前**调它;server 记进程内 `drainState.reason`,draining 期由 `/health` 的 `drainReason` 与 503 `draining` 体的 `reason` 透出(未声明 = 两面键缺席)。声明是**覆盖式**、无 TTL、随进程重启清零 ⇒ 每次停机流程内都要重新声明。`reason` 非空、trim 后 ≤256 字符,坏值 400。🔴 **写口是特权的,读口不是**:`/health` 免鉴权(见下一行)且缺省全网卡监听 —— 任何能连到这个端口的人都读得到你写的那句话。**别在 reason 里写工单号、内部主机名或任何内部标识**。 |
1078
+ | `POST /v1/admin/drain` `{"reason":"…"}` | **停机因由显式声明**(7.35.0+;operator-only —— principal 须在 `OPERATOR_PRINCIPALS` 内,空名单 = 谁都不是 operator ⇒ 恒 403)。设计给编排层(k8s `preStop` / systemd `ExecStop` 等)在发 SIGTERM **之前**调用声明因由;⚠️ **如实**:本仓四条消费树(server/cli/sdk/web-admin)与编排层脚本树 `sema-deploy` 里对它零调用,`sema-comms audits/.md:213` N-18 已把它书面登记为 declined(cli 判定这是 operator 面,不是壳自动打的口)—— 今天它是给**运维手动 curl**(或运维自己写的编排脚本)用的口,不是任何一个内置壳自动调用的。调用后 server 记进程内 `drainState.reason`,draining 期由 `/health` 的 `drainReason` 与 503 `draining` 体的 `reason` 透出(未声明 = 两面键缺席)。声明是**覆盖式**、无 TTL、随进程重启清零 ⇒ 每次停机流程内都要重新声明。`reason` 非空、trim 后 ≤256 字符,坏值 400。无 drain 面装配(嵌入宿主 / 测试)上声明无处可落 ⇒ 501 `capability.drain_state_required`。🔴 **写口是特权的,读口不是**:`/health` 免鉴权(见下一行)且缺省全网卡监听 —— 任何能连到这个端口的人都读得到你写的那句话。**别在 reason 里写工单号、内部主机名或任何内部标识**。 |
1079
1079
  | `GET /v1/config/catalog` | **配置目录自描述**(operator-only —— `explicitOperatorOk`,空名单=谁都不是)。逐 env 键一行:`{name, domain, type, semantics, writeLanes, effectiveLane, envHeld, envTiming, staticDefault?/derivedDefaultNote?, effectiveValue, valueClass, danger, center?{domain,path,precedence,timing,restartSlice?,domainExists,managedNow,effectiveNow}}`;顶层带 `restartSlices`(重启片闭集)与 `centerDomains`(settings-schema 现行域表)。**两轴不混**:`writeLanes`=谁能写,`effectiveLane`=现在谁在生效(env-wins 族 env 占位 ⇒ center 腿 `effectiveNow:false`)。secret 类值**永不回传**(只回在场位;opaque 回在场位+长度;URL 剥 userinfo)。完备性由仓内 AST 双向对账门执法(分母=全 `src/` 生产 env 读取点)。旋钮 `CONFIG_CATALOG_ENABLED=false`(合规部署)⇒ 路径 404 + 能力位 `configCatalog:false`。响应 `Cache-Control: no-store`。**7.57.0 起**:`enum` 行的 `effectiveValue` **恒落在该行自己的 `enumValues` 闭集内**(仓内机器门执法)——此前 `SESSION_BACKEND` 回的是**内部标签** `tidb`(自 5.0.0 起是**退役公名**,写回去 boot 拒),现归一成公名 `mysql`;`MODEL_DEFAULT_THINKING` 补上一直被解析器接受、却漏在目录闭集外的 `xhigh`,并改为回**实算值**(`off`/未设 ⇒ `null`)而不是 env 原文。 |
1080
1080
  | `POST /v1/admin/config/refresh` | **配置手动刷新**(operator-only,与上一行同门:空 `OPERATOR_PRINCIPALS` ⇒ 恒 403)。改完中心配置 / `config.d` 之后不想等 60s 轮询就调它:触发**一次既有**的 refresh 拍(在飞则汇入那一拍,绝不并发双拍),返回时该拍已落地。200 体 `{triggered:true,targetVersion,appliedVersion}` —— 两个世代号与 `/health` 的 `configTargetVersion`/`configAppliedVersion` 同源。本部署没有配置管道(纯 env worker:既没配 `CONFIG_CENTER`、也不是 `CONFIG_PROVIDER=local`)⇒ 409 `config.refresh_unavailable` 指路,不会回一个「触发了但什么都没发生」的 200。 |
1081
1081
  | `GET /health` | 健康(无需鉴权)。**7.67.0+** 恒带 `startedAt`(引擎进程起点 epoch ms,一次铸;与 `pid` 并列的换代锚——值变了就是换了一条命)。7.37.0+ 配置管道在场时带世代账键:`configTargetVersion`(本副本**最后见到**的配置版本,身份标)、`configAppliedVersion`(最后一次真落地的版本)、`configTargetOrdinal`/`configAppliedOrdinal`(7.38.0-rc.2 起,**收货序数**——`CONFIG_PROVIDER=local` 下 version 是内容哈希不承诺序,「改了没生效」看序数对不对齐)、`configApplyStaleMs`(target≠applied **持续**时长;收敛时键缺席)—— 编排器据此摘掉「配置持续落后」的副本 |
@@ -94,9 +94,13 @@ type _GuardWiringFleet = AssertAllKeysHandled<Exclude<keyof WiringSection<"fleet
94
94
  type _GuardWiringFleetReverse = AssertAllKeysHandled<Exclude<WiringFleetHandled, keyof WiringSection<"fleet">>>;
95
95
  type WiringMcpEntry = WiringSection<"mcp">[number];
96
96
  type WiringMcpExcluded = "error";
97
- type WiringMcpHandled = "name" | "source" | "status" | "errorCode" | "delivered" | "httpStatus" | "toolCount" | WiringMcpExcluded;
97
+ type WiringMcpHandled = "name" | "source" | "status" | "errorCode" | "delivered" | "httpStatus" | "toolCount" | "liveness" | WiringMcpExcluded;
98
98
  type _GuardWiringMcp = AssertAllKeysHandled<Exclude<keyof WiringMcpEntry, WiringMcpHandled>>;
99
99
  type _GuardWiringMcpReverse = AssertAllKeysHandled<Exclude<WiringMcpHandled, keyof WiringMcpEntry>>;
100
+ type WiringMcpLiveness = NonNullable<WiringMcpEntry["liveness"]>;
101
+ type WiringMcpLivenessHandled = "state" | "observedAt" | "errorCode";
102
+ type _GuardWiringMcpLiveness = AssertAllKeysHandled<Exclude<keyof WiringMcpLiveness, WiringMcpLivenessHandled>>;
103
+ type _GuardWiringMcpLivenessReverse = AssertAllKeysHandled<Exclude<WiringMcpLivenessHandled, keyof WiringMcpLiveness>>;
100
104
  type WiringRulesHandled = "storeWired" | "syncWired" | "orgGoverned";
101
105
  type _GuardWiringRules = AssertAllKeysHandled<Exclude<keyof WiringSection<"permissionRules">, WiringRulesHandled>>;
102
106
  type _GuardWiringRulesReverse = AssertAllKeysHandled<Exclude<WiringRulesHandled, keyof WiringSection<"permissionRules">>>;
@@ -180,12 +184,12 @@ type _GuardMcpReconnect = AssertAllKeysHandled<Exclude<keyof McpReconnectResult,
180
184
  type _NoDoubleBookMcpReconnect = AssertAllKeysHandled<Extract<McpReconnectProjected, McpReconnectWithheld>>;
181
185
  type _GuardMcpReconnectReverse = AssertAllKeysHandled<Exclude<McpReconnectProjected | McpReconnectWithheld, keyof McpReconnectResult>>;
182
186
  type McpRedialStatusProjected = "name" | "status" | "errorCode" | "httpStatus" | "delivered" | "serverInfo" | "error" | "transportClosed";
183
- type McpRedialStatusWithheld = "toolNames";
187
+ type McpRedialStatusWithheld = "toolNames" | "liveness";
184
188
  type _GuardMcpRedialStatus = AssertAllKeysHandled<Exclude<keyof McpServerStatus, McpRedialStatusProjected | McpRedialStatusWithheld>>;
185
189
  type _NoDoubleBookMcpRedialStatus = AssertAllKeysHandled<Extract<McpRedialStatusProjected, McpRedialStatusWithheld>>;
186
190
  type _GuardMcpRedialStatusReverse = AssertAllKeysHandled<Exclude<McpRedialStatusProjected | McpRedialStatusWithheld, keyof McpServerStatus>>;
187
191
  type McpPanelStatusProjected = "name" | "status" | "serverInfo" | "toolNames" | "error";
188
- type McpPanelStatusWithheld = "errorCode" | "httpStatus" | "delivered" | "transportClosed";
192
+ type McpPanelStatusWithheld = "errorCode" | "httpStatus" | "delivered" | "transportClosed" | "liveness";
189
193
  type _GuardMcpPanelStatus = AssertAllKeysHandled<Exclude<keyof McpServerStatus, McpPanelStatusProjected | McpPanelStatusWithheld>>;
190
194
  type _NoDoubleBookMcpPanelStatus = AssertAllKeysHandled<Extract<McpPanelStatusProjected, McpPanelStatusWithheld>>;
191
195
  type _GuardMcpPanelStatusReverse = AssertAllKeysHandled<Exclude<McpPanelStatusProjected | McpPanelStatusWithheld, keyof McpServerStatus>>;
@@ -288,7 +292,9 @@ export type CoreKeysetGuards = [
288
292
  _NoDoubleBookMcpPanelStatus,
289
293
  _GuardMcpPanelStatusReverse,
290
294
  _GuardMcpListingIncomplete,
291
- _GuardMcpListingIncompleteReverse
295
+ _GuardMcpListingIncompleteReverse,
296
+ _GuardWiringMcpLiveness,
297
+ _GuardWiringMcpLivenessReverse
292
298
  ];
293
299
  export {};
294
300
  //# sourceMappingURL=core-keyset-guard.d.ts.map
@@ -585,6 +585,22 @@ export declare function workspaceChangedEventData(ev: {
585
585
  * (「connection state is a fact about this leg's attempt, not about the assembly」)。
586
586
  * ⚠️ 空数组 ≠ 缺席:core 顶注逐字「an empty array is "this leg declared no servers", absence is an older
587
587
  * mint or an external derivation」⇒ 空数组照铸,别折成缺席。
588
+ * 🔴 **⑤ `liveness`(core 7.24.3 [ref] / S-402 提货件)—— 裁:租户可见,整条记录投,逐键挑**。
589
+ * `{state, observedAt, errorCode?}` = 引擎**最后一次观察**到的「这台还够得着吗」。受众判据与同行
590
+ * 其余键**同一条**(同主体同受众、引擎派生的闭形值、非 governance 侧信道 —— 它同样不进
591
+ * `configFingerprint`),所以这一格不需要新的裁定,只需要新的**读法**。
592
+ * 🔴 **契约一行(client-core CC-36 的那句话):活性位独立于名册申报与 re-dial 结果。**
593
+ * `status` 是拨号那一刻的判决且 core **有意冻结**(服务器中途死了仍读 `connected`);re-dial 回执的
594
+ * `outcome` 是一次动作的判词;这一格是连接层最后学到的事,自带时戳。三者**合法地可以不一致** ——
595
+ * `status:"failed"` 与 `liveness.state:"reachable"` 同行是真行(服务器答了握手、答的是协议错:
596
+ * 活着,且配错了)。⇒ 本仓**不合并、不互相校验、不据一个推另一个**(与 ① 里「两条 MCP 读面同名
597
+ * 不同源、合并只会造出『哪个才算数』」逐字同源)。
598
+ * ⚠️ **缺席是第四读数,不是一个词**:core 顶注逐字「a consumer must not fold absence into
599
+ * `unknown`」——`unknown` 是**更强**的断言(引擎看了、看不出来)。
600
+ * 🔴 **但本仓出口上的「缺席」比 core 源端的更宽**(codex r1 [medium] 采纳):core 那边是
601
+ * 压根没有观察(`skipped` 的行没走到 transport / `invalid_config` 的声明从没被拨过 / 老 mint),
602
+ * 而经过本投影后**判形没过也落缺席**(词出闭集 / `observedAt` 非有限数 / 整只不是对象)。
603
+ * ⇒ 对消费端,缺席只能读成「**没有可用的观察记录**」,**不许**据它反推这条腿拨没拨过号。
588
604
  * · `writeProtection`(`{ targetView: "spelling-only" | "target" }`;core 7.20.1 [ref] / clay [ref] 丙,
589
605
  * S-361 提货件)—— **裁:租户可见,逐字透传**。它是 per-leg 的读面:「这条腿的写保护判官,拿到的是
590
606
  * 哪一种目标读法」——`"target"` = 判官握着执行环境,拼法没命中时会在**解析后的真目标**上再判一次;
@@ -1,5 +1,5 @@
1
1
  import { redactErrorMessage, redactModelText } from "../observability/run-terminal.js";
2
- import { MCP_DELIVERY_VERDICTS, screenGateOutcome, ToolRoster, ToolRosterDelta, WRITE_PROTECTION_TARGET_VIEWS } from "@sema-agent/core";
2
+ import { MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, screenGateOutcome, ToolRoster, ToolRosterDelta, WRITE_PROTECTION_TARGET_VIEWS } from "@sema-agent/core";
3
3
  import { Value } from "typebox/value";
4
4
  import { recordFailOpen } from "../observability/fail-open.js";
5
5
  import { redactSecrets, redactDeep } from "./redact.js";
@@ -507,6 +507,17 @@ export function wiringManifestEventData(ev) {
507
507
  const status = str(e.status);
508
508
  if (name === undefined || status === undefined)
509
509
  continue;
510
+ const liveness = (() => {
511
+ const rec = sec(e.liveness);
512
+ if (rec === undefined)
513
+ return undefined;
514
+ const state = str(rec.state);
515
+ const observedAt = num(rec.observedAt);
516
+ if (state === undefined || !MCP_LIVENESS_STATES.includes(state) || observedAt === undefined)
517
+ return undefined;
518
+ const errorCode = str(rec.errorCode);
519
+ return { state, observedAt, ...(errorCode === undefined ? {} : { errorCode }) };
520
+ })();
510
521
  rows.push({
511
522
  name,
512
523
  status,
@@ -515,6 +526,7 @@ export function wiringManifestEventData(ev) {
515
526
  ...(str(e.errorCode) !== undefined ? { errorCode: e.errorCode } : {}),
516
527
  ...(typeof e.delivered === "string" && MCP_DELIVERY_VERDICTS.includes(e.delivered) ? { delivered: e.delivered } : {}),
517
528
  ...(num(e.httpStatus) !== undefined ? { httpStatus: e.httpStatus } : {}),
529
+ ...(liveness !== undefined ? { liveness } : {}),
518
530
  });
519
531
  }
520
532
  return rows;
@@ -590,9 +590,11 @@ function collectStickySpans(a, text, at, out) {
590
590
  }
591
591
  }
592
592
  const WORD_SEGMENT_CLASS = "[A-Za-z0-9._~+/-]";
593
+ const LEXICAL_KEYWORD_ARMS = new Set();
593
594
  const keywordArm = (keywordSrc, valueClass, min, tailSrc = "") => {
594
595
  const re = new RegExp(`(?:${keywordSrc}\\s+${atLeast(valueClass, min)}${tailSrc}` +
595
596
  `|(?<!${WORD_SEGMENT_CLASS})${keywordSrc}(?:${twoStrongAhead(valueClass)}|${noConnectorAhead(valueClass)})${atLeast(valueClass, min)}${tailSrc})`, "g");
597
+ LEXICAL_KEYWORD_ARMS.add(re);
596
598
  return re;
597
599
  };
598
600
  const CREDENTIAL_NAME_WORDS = [
@@ -1515,6 +1517,7 @@ const armPool = (() => {
1515
1517
  rank,
1516
1518
  order,
1517
1519
  phase: 1,
1520
+ lexical: LEXICAL_KEYWORD_ARMS.has(re),
1518
1521
  collect: boundary === undefined
1519
1522
  ? (text, _json, _observe, out) => collectRegexSpans(arm, text, out)
1520
1523
  : (text, _json, _observe, out) => collectValueArmSpans(boundary, text, out),
@@ -1530,6 +1533,7 @@ const armPool = (() => {
1530
1533
  rank: ARM_RANK.structural,
1531
1534
  order,
1532
1535
  phase,
1536
+ lexical: false,
1533
1537
  collect: (text, json, observe, out) => scan(text, json, observe, (start, end) => out.push({ start, end, repl, rank: ARM_RANK.structural, order })),
1534
1538
  retry: undefined,
1535
1539
  headSrc: undefined,
@@ -1554,14 +1558,32 @@ const armPool = (() => {
1554
1558
  members.push(regexMember(row, ARM_RANK.shape, members.length, false));
1555
1559
  for (const row of FRAGMENT_SECRET_PATTERNS)
1556
1560
  members.push(regexMember(row, ARM_RANK.fragment, members.length, false));
1561
+ for (const [re] of KEYWORD_SECRET_PATTERNS) {
1562
+ if (!LEXICAL_KEYWORD_ARMS.has(re))
1563
+ throw new Error(`redact: keyword arm /${re.source}/ is not registered as lexical — build it with keywordArm() so the bounded-unit scope can exclude it`);
1564
+ }
1557
1565
  const retryMembers = members.filter((m) => m.retry !== undefined);
1558
1566
  const phase1 = members.filter((m) => m.phase === 1);
1559
1567
  const phase2 = members.filter((m) => m.phase === 2);
1568
+ const laneOf = (scope) => {
1569
+ const inScope = (m) => {
1570
+ switch (scope) {
1571
+ case "free-text": return true;
1572
+ case "bounded-unit": return !m.lexical;
1573
+ }
1574
+ };
1575
+ return { phase1: phase1.filter(inScope), phase2: phase2.filter(inScope), retry: retryMembers.filter(inScope) };
1576
+ };
1577
+ const LANES = {
1578
+ "free-text": laneOf("free-text"),
1579
+ "bounded-unit": laneOf("bounded-unit"),
1580
+ };
1560
1581
  const headScreen = new RegExp(`(?:${retryMembers.map((m) => m.headSrc).join("|")})`, "y");
1561
1582
  const headFirstUnit = unionMembers(retryMembers.map((m) => m.headFirst)) ?? new Uint32Array(0x10000 >>> 5).fill(0xffffffff);
1562
1583
  poolArmCount = members.length;
1563
1584
  poolBoundaryArmCount = retryMembers.length;
1564
- return (text, wantCount, json, observe) => {
1585
+ return (text, wantCount, json, observe, scope) => {
1586
+ const lane = LANES[scope];
1565
1587
  const spans = [];
1566
1588
  let tried;
1567
1589
  const freshCovered = (from) => {
@@ -1586,25 +1608,25 @@ const armPool = (() => {
1586
1608
  return at.sort((x, y) => x - y);
1587
1609
  };
1588
1610
  const closeCoveragePositions = (from) => {
1589
- if (retryMembers.length === 0 || spans.length === from)
1611
+ if (lane.retry.length === 0 || spans.length === from)
1590
1612
  return;
1591
1613
  for (let at = freshCovered(from); at.length > 0;) {
1592
1614
  const before = spans.length;
1593
- for (const m of retryMembers)
1615
+ for (const m of lane.retry)
1594
1616
  m.retry(text, at, spans);
1595
1617
  at = freshCovered(before);
1596
1618
  }
1597
1619
  };
1598
1620
  setScanEvidence(NO_CREDENTIAL_SPANS);
1599
- for (const m of phase1)
1621
+ for (const m of lane.phase1)
1600
1622
  m.collect(text, json, observe, spans);
1601
1623
  closeCoveragePositions(0);
1602
- if (phase2.length > 0) {
1624
+ if (lane.phase2.length > 0) {
1603
1625
  let evidence = credentialSpans(text, spans, false);
1604
1626
  for (let level = 0;; level += 1) {
1605
1627
  const before = spans.length;
1606
1628
  setScanEvidence(evidence);
1607
- for (const m of phase2)
1629
+ for (const m of lane.phase2)
1608
1630
  m.collect(text, json, observe && level === 0, spans);
1609
1631
  closeCoveragePositions(before);
1610
1632
  forensicLevels += 1;
@@ -1646,8 +1668,8 @@ let onRedaction;
1646
1668
  export function setRedactionObserver(fn) {
1647
1669
  onRedaction = fn;
1648
1670
  }
1649
- function applyRules(text, wantCount, json, observe) {
1650
- return armPool(text, wantCount, json, observe);
1671
+ function applyRules(text, wantCount, json, observe, scope) {
1672
+ return armPool(text, wantCount, json, observe, scope);
1651
1673
  }
1652
1674
  function reportHits(hits) {
1653
1675
  if (onRedaction === undefined)
@@ -1660,20 +1682,20 @@ function reportHits(hits) {
1660
1682
  }
1661
1683
  }
1662
1684
  }
1663
- function runRedaction(text, observe, json, wantHits) {
1685
+ function runRedaction(text, observe, json, wantHits, scope) {
1664
1686
  const wantCount = wantHits || (onRedaction !== undefined && observe);
1665
1687
  const normalized = normalizeForRedaction(text);
1666
- const r = applyRules(normalized, wantCount, json, observe);
1688
+ const r = applyRules(normalized, wantCount, json, observe, scope);
1667
1689
  forgetEscapedSeparatorTails();
1668
1690
  if (observe)
1669
1691
  reportHits(r.hits);
1670
1692
  return { text: r.out, hits: r.hits, spans: r.kept };
1671
1693
  }
1672
1694
  export function redactSecrets(text, opts) {
1673
- return runRedaction(text, opts?.observe ?? true, opts?.json === true, false).text;
1695
+ return runRedaction(text, opts?.observe ?? true, opts?.json === true, false, "free-text").text;
1674
1696
  }
1675
1697
  export function redactSecretsWithArms(text, opts) {
1676
- const r = runRedaction(text, opts?.observe ?? true, opts?.json === true, true);
1698
+ const r = runRedaction(text, opts?.observe ?? true, opts?.json === true, true, "free-text");
1677
1699
  return { text: r.text, arms: new Set(r.hits.map((h) => h.arm)) };
1678
1700
  }
1679
1701
  const REDACT_MAX_DEPTH = 64;
@@ -1777,7 +1799,7 @@ function unitCarriesCredential(unit) {
1777
1799
  for (const v of armValueClassViews())
1778
1800
  views.add(boundedUnitView(spelling, v.inClass, v.filler));
1779
1801
  views.delete("");
1780
- const hit = [...views].some((view) => redactSecrets(view) !== view);
1802
+ const hit = [...views].some((view) => runRedaction(view, true, false, false, "bounded-unit").text !== view);
1781
1803
  return { hit, residue: decoded.residue };
1782
1804
  }
1783
1805
  function displaySafePathname(pathname) {
@@ -1808,7 +1830,7 @@ function shapeLawCredentialInQueryOrFragment(canonical) {
1808
1830
  const boundary = normalized.indexOf("?");
1809
1831
  if (boundary < 0)
1810
1832
  return false;
1811
- if (runRedaction(canonical, false, false, false).spans.some((sp) => sp.end > boundary))
1833
+ if (runRedaction(canonical, false, false, false, "free-text").spans.some((sp) => sp.end > boundary))
1812
1834
  return true;
1813
1835
  for (const unit of normalized.slice(boundary + 1).split("&").flatMap((sg) => {
1814
1836
  const eq = sg.indexOf("=");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/server",
3
- "version": "7.91.1",
3
+ "version": "7.91.2",
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",
@@ -59,7 +59,7 @@
59
59
  "build:binary:run-local:darwin-arm64": "bun build --compile --target=bun-darwin-arm64 src/run-local.ts --outfile dist/run-local-darwin-arm64"
60
60
  },
61
61
  "dependencies": {
62
- "@sema-agent/core": "7.24.2",
62
+ "@sema-agent/core": "7.24.4",
63
63
  "@sema-agent/settings-schema": "3.0.0",
64
64
  "e2b": "^2.28.0",
65
65
  "libsodium-wrappers": "^0.8.4",
@@ -74,7 +74,7 @@
74
74
  "sharp": "^0.35.3"
75
75
  },
76
76
  "devDependencies": {
77
- "@sema-agent/sdk": "9.10.0",
77
+ "@sema-agent/sdk": "9.11.0",
78
78
  "@types/libsodium-wrappers": "^0.7.14",
79
79
  "@types/node": "22.10.2",
80
80
  "@types/pg": "^8.20.0",