@sema-agent/settings-schema 1.7.1 → 1.8.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.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,25 @@
6
6
  > `@sema-agent/registry-core`(更早还曾是 `@sema-ai/registry-core`)。本档 `0.19.0` 以下各节里的
7
7
  > 包名是**历史记录**,如实保留不追改。
8
8
 
9
+ ## 1.8.0 — 2026-09-07 — `ModelRole` 闭集对齐 core:加 `classifier` / `consolidate`(新词=minor)
10
+
11
+ - cli [6554] 真案:core `ModelRole` 早有 `classifier`(auto 权限分类器,FALLBACK classifier→summarize→default、tier 缺省 flash)
12
+ 与 `consolidate`(记忆整理),本闭集没跟上 ⇒ settings 写 `models.roles.classifier` 被 schema 拒,用户想单独钉分类器模型
13
+ 只能连带 summarize(或走 `MODEL_CHEAP_ID` 连带 subagent)。1.8.0 起两词合法;`advisor`(teacher mode)仍刻意排除(无消费方)。
14
+ - **roster 标记族不动**(`ROSTER_CHEAP_ROLES` 仍 subagent/summarize):新角色不派生、走 core 兜底链、只由 settings 显式钉——
15
+ 归 cheap 会让消费方把它钉死到 cheapRef,盖掉 `models.tiers.flash` 档位。反向门改为显式登记三个不派生角色各自理由。
16
+ - 消费方:sema-server 经 `apply-effective` 逐键落 `config.roles`,零改;server 侧加编译期子集钉(schema ⊆ core)。
17
+ - 红先:`test/model-role-1.8.test.ts`(1.7.2 上两格红)+ `resolve-roster.test.ts` 反向门更新。
18
+
19
+ ## 1.7.2 — 2026-09-06 — `source` 改**解析透明**(`z.unknown()`;patch)
20
+
21
+ - 1.7.1 的 `z.string()` 对 `source: null`(或数字/数组/对象)仍在解析处拒 ⇒ 整域 all-or-nothing 下**一个**非串标签让整套
22
+ `mcp.servers` 默认为空——而 1.6.0 之前该键被 default-strip 剥掉、无害,故这是 1.7.x 引入的**升级回归**(消费方 codex
23
+ 对抗复审 [high],`buildEffective` 与 `readEffectiveWire` 两腿复现)。1.7.2 起 `source: z.unknown().optional()`:
24
+ 任何 JSON 值原样到消费方,规则(非空 ≤80 字符串)与坏形处置(丢键留 server + 留痕)**只**在消费方一处。
25
+ - 红先:`test/mcp-source-label.test.ts` ③ 改「七形全过、原样」+ ③b「坏标签兄弟不拖累好 server」。
26
+ - 类病(任一字段解析拒 ⇒ 整域默认)仍归消费方 S-144 另车。
27
+
9
28
  ## 1.7.1 — 2026-09-06 — `source` 改**只管类型**(撤回 1.7.0 的 min/max 解析拒;patch)
10
29
 
11
30
  - 1.7.0 把标签规则(非空 ≤80)写进 zod ⇒ 本域整域 all-or-nothing 解析下,**一个**空/超长标签让整套 `mcp.servers`
@@ -1,7 +1,8 @@
1
1
  import { stableHash } from "./hash.js";
2
2
  import { toSkillsManifest } from "./skills-manifest.js";
3
3
  // ── 主/cheap 角色标记语义(0.6.3, E3)────────────────────────────────
4
- // service 现有 ModelRoles 口径:default/team/synthesize→主、subagent/summarize→cheap。`verifier` 刻意
4
+ // service 现有 ModelRoles 口径:default/team/synthesize→主、subagent/summarize→cheap。1.8.0 起 `classifier`/`consolidate`
5
+ // 同 `verifier` 一样**不派生**(归 cheap 会盖掉 models.tiers 档位与 core 兜底链)。`verifier` 刻意
5
6
  // 不派生(unset→core 的 default 兜底链,与 service 语义一致)。常量导出=单一语义源,service 收敛小单与
6
7
  // center 表单同源引用,别第二份。
7
8
  /** primaryModel 标记喂的角色族(§3)。 */
package/dist/types.d.ts CHANGED
@@ -315,7 +315,7 @@ export declare const ModelEntry: z.ZodEffects<z.ZodObject<{
315
315
  notes?: string | undefined;
316
316
  }>;
317
317
  export type ModelEntry = z.infer<typeof ModelEntry>;
318
- export declare const ModelRole: z.ZodEnum<["default", "summarize", "subagent", "team", "synthesize", "verifier"]>;
318
+ export declare const ModelRole: z.ZodEnum<["default", "summarize", "subagent", "team", "synthesize", "verifier", "classifier", "consolidate"]>;
319
319
  export type ModelRole = z.infer<typeof ModelRole>;
320
320
  /** A role resolves either to a model NAME, or by capability/price (core 1.25 `{ select }`). */
321
321
  export declare const RoleTarget: z.ZodUnion<[z.ZodObject<{
@@ -640,7 +640,7 @@ export declare const ModelsConfig: z.ZodEffects<z.ZodObject<{
640
640
  * superRefine);未经 schema 的本地/存量 lane 由消费方 warn 降级(与 activeTierGroup 双层姿势一致)。 */
641
641
  default: z.ZodOptional<z.ZodString>;
642
642
  /** role → target. Unset roles fall back to `default` (core fallback chain). */
643
- roles: z.ZodDefault<z.ZodRecord<z.ZodEnum<["default", "summarize", "subagent", "team", "synthesize", "verifier"]>, z.ZodUnion<[z.ZodObject<{
643
+ roles: z.ZodDefault<z.ZodRecord<z.ZodEnum<["default", "summarize", "subagent", "team", "synthesize", "verifier", "classifier", "consolidate"]>, z.ZodUnion<[z.ZodObject<{
644
644
  model: z.ZodString;
645
645
  }, "strip", z.ZodTypeAny, {
646
646
  model: string;
@@ -755,7 +755,7 @@ export declare const ModelsConfig: z.ZodEffects<z.ZodObject<{
755
755
  extraBody?: Record<string, unknown> | undefined;
756
756
  notes?: string | undefined;
757
757
  }[];
758
- roles: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
758
+ roles: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
759
759
  model: string;
760
760
  } | {
761
761
  select: {
@@ -812,7 +812,7 @@ export declare const ModelsConfig: z.ZodEffects<z.ZodObject<{
812
812
  enabled?: boolean | undefined;
813
813
  notes?: string | undefined;
814
814
  }[] | undefined;
815
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
815
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
816
816
  model: string;
817
817
  } | {
818
818
  select: {
@@ -867,7 +867,7 @@ export declare const ModelsConfig: z.ZodEffects<z.ZodObject<{
867
867
  extraBody?: Record<string, unknown> | undefined;
868
868
  notes?: string | undefined;
869
869
  }[];
870
- roles: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
870
+ roles: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
871
871
  model: string;
872
872
  } | {
873
873
  select: {
@@ -924,7 +924,7 @@ export declare const ModelsConfig: z.ZodEffects<z.ZodObject<{
924
924
  enabled?: boolean | undefined;
925
925
  notes?: string | undefined;
926
926
  }[] | undefined;
927
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
927
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
928
928
  model: string;
929
929
  } | {
930
930
  select: {
@@ -955,14 +955,14 @@ export declare const RosterEntry: z.ZodObject<{
955
955
  /**
956
956
  * 主模型角色标记(0.6.3, E3)——catalog model NAME。worker.model 废除后 service 从 roster
957
957
  * 解析 boot 主模型的归宿位:解析语义(resolve-roster)= primary 喂 `default`/`team`/`synthesize` 三角色、
958
- * cheap 喂 `subagent`/`summarize`(service 现有 ModelRoles 口径;`verifier` 不派生——unset→default 兜底链)。
958
+ * cheap 喂 `subagent`/`summarize`(service 现有 ModelRoles 口径;`verifier`/`classifier`/`consolidate` 不派生——unset 走 core 兜底链)。
959
959
  * 显式 `roles` **逐角色**优先于标记派生;标记优先于全局 models.roles。additive:不设=行为与 0.6.2 全等。
960
960
  */
961
961
  primaryModel: z.ZodOptional<z.ZodString>;
962
962
  /** cheap 模型角色标记(同上;worker.model.cheapId 的迁移归宿,§3②)。 */
963
963
  cheapModel: z.ZodOptional<z.ZodString>;
964
964
  /** Role map override; unset roles fall back to marker-derived roles, then the global models.roles. */
965
- roles: z.ZodOptional<z.ZodRecord<z.ZodEnum<["default", "summarize", "subagent", "team", "synthesize", "verifier"]>, z.ZodUnion<[z.ZodObject<{
965
+ roles: z.ZodOptional<z.ZodRecord<z.ZodEnum<["default", "summarize", "subagent", "team", "synthesize", "verifier", "classifier", "consolidate"]>, z.ZodUnion<[z.ZodObject<{
966
966
  model: z.ZodString;
967
967
  }, "strip", z.ZodTypeAny, {
968
968
  model: string;
@@ -1002,7 +1002,7 @@ export declare const RosterEntry: z.ZodObject<{
1002
1002
  name: string;
1003
1003
  models: string[];
1004
1004
  notes?: string | undefined;
1005
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
1005
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
1006
1006
  model: string;
1007
1007
  } | {
1008
1008
  select: {
@@ -1018,7 +1018,7 @@ export declare const RosterEntry: z.ZodObject<{
1018
1018
  name: string;
1019
1019
  notes?: string | undefined;
1020
1020
  models?: string[] | undefined;
1021
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
1021
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
1022
1022
  model: string;
1023
1023
  } | {
1024
1024
  select: {
@@ -1040,14 +1040,14 @@ export declare const RostersConfig: z.ZodEffects<z.ZodObject<{
1040
1040
  /**
1041
1041
  * 主模型角色标记(0.6.3, E3)——catalog model NAME。worker.model 废除后 service 从 roster
1042
1042
  * 解析 boot 主模型的归宿位:解析语义(resolve-roster)= primary 喂 `default`/`team`/`synthesize` 三角色、
1043
- * cheap 喂 `subagent`/`summarize`(service 现有 ModelRoles 口径;`verifier` 不派生——unset→default 兜底链)。
1043
+ * cheap 喂 `subagent`/`summarize`(service 现有 ModelRoles 口径;`verifier`/`classifier`/`consolidate` 不派生——unset 走 core 兜底链)。
1044
1044
  * 显式 `roles` **逐角色**优先于标记派生;标记优先于全局 models.roles。additive:不设=行为与 0.6.2 全等。
1045
1045
  */
1046
1046
  primaryModel: z.ZodOptional<z.ZodString>;
1047
1047
  /** cheap 模型角色标记(同上;worker.model.cheapId 的迁移归宿,§3②)。 */
1048
1048
  cheapModel: z.ZodOptional<z.ZodString>;
1049
1049
  /** Role map override; unset roles fall back to marker-derived roles, then the global models.roles. */
1050
- roles: z.ZodOptional<z.ZodRecord<z.ZodEnum<["default", "summarize", "subagent", "team", "synthesize", "verifier"]>, z.ZodUnion<[z.ZodObject<{
1050
+ roles: z.ZodOptional<z.ZodRecord<z.ZodEnum<["default", "summarize", "subagent", "team", "synthesize", "verifier", "classifier", "consolidate"]>, z.ZodUnion<[z.ZodObject<{
1051
1051
  model: z.ZodString;
1052
1052
  }, "strip", z.ZodTypeAny, {
1053
1053
  model: string;
@@ -1087,7 +1087,7 @@ export declare const RostersConfig: z.ZodEffects<z.ZodObject<{
1087
1087
  name: string;
1088
1088
  models: string[];
1089
1089
  notes?: string | undefined;
1090
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
1090
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
1091
1091
  model: string;
1092
1092
  } | {
1093
1093
  select: {
@@ -1103,7 +1103,7 @@ export declare const RostersConfig: z.ZodEffects<z.ZodObject<{
1103
1103
  name: string;
1104
1104
  notes?: string | undefined;
1105
1105
  models?: string[] | undefined;
1106
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
1106
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
1107
1107
  model: string;
1108
1108
  } | {
1109
1109
  select: {
@@ -1121,7 +1121,7 @@ export declare const RostersConfig: z.ZodEffects<z.ZodObject<{
1121
1121
  name: string;
1122
1122
  models: string[];
1123
1123
  notes?: string | undefined;
1124
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
1124
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
1125
1125
  model: string;
1126
1126
  } | {
1127
1127
  select: {
@@ -1139,7 +1139,7 @@ export declare const RostersConfig: z.ZodEffects<z.ZodObject<{
1139
1139
  name: string;
1140
1140
  notes?: string | undefined;
1141
1141
  models?: string[] | undefined;
1142
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
1142
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
1143
1143
  model: string;
1144
1144
  } | {
1145
1145
  select: {
@@ -1157,7 +1157,7 @@ export declare const RostersConfig: z.ZodEffects<z.ZodObject<{
1157
1157
  name: string;
1158
1158
  models: string[];
1159
1159
  notes?: string | undefined;
1160
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
1160
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
1161
1161
  model: string;
1162
1162
  } | {
1163
1163
  select: {
@@ -1175,7 +1175,7 @@ export declare const RostersConfig: z.ZodEffects<z.ZodObject<{
1175
1175
  name: string;
1176
1176
  notes?: string | undefined;
1177
1177
  models?: string[] | undefined;
1178
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
1178
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
1179
1179
  model: string;
1180
1180
  } | {
1181
1181
  select: {
@@ -7322,16 +7322,18 @@ export declare const McpServerSpec: z.ZodObject<{
7322
7322
  * consumer can group servers by where they were declared). An OPEN set: CC's `plugin` / `user` /
7323
7323
  * `project` / `local` are conventions, not a vocabulary — a deployment's own word is equally legal, so
7324
7324
  * no closed table here (a closed table would reject the operator's grouping word at parse). ABSENT =
7325
- * no label (`.optional()`, no default — a label has no default tier). 🔴 TYPE-ONLY here (any string):
7326
- * the label RULE (non-empty, ≤80 chars) lives in ONE place — the consumer's projection helper, which
7327
- * drops a malformed label's KEY, keeps the server and records the drop. It deliberately does NOT live
7328
- * here: this domain parses all-or-nothing, so a `min(1)`/`max(80)` at parse would let one empty label
7329
- * default the ENTIRE mcp domain (every server gone) — a blast radius a display label must never have
7330
- * (1.7.0 shipped that shape for a few hours; 1.7.1 retracts it). Display-only: no gate / policy / trust
7325
+ * no label (`.optional()`, no default — a label has no default tier). 🔴 ZERO rules here (`z.unknown()`):
7326
+ * the label RULE (string, non-empty, ≤80 chars) lives in ONE place — the consumer's projection helper,
7327
+ * which drops a malformed label's KEY, keeps the server and records the drop. Nothing may live here:
7328
+ * this domain parses all-or-nothing, so ANY rejection at parse (1.7.0 `min/max`, 1.7.1 `z.string()`
7329
+ * against a `null`) lets one bad label default the ENTIRE mcp domain — every server gone, silently when
7330
+ * no onWarning is wired — a blast radius a display label must never have. 1.7.2 makes the key
7331
+ * parse-transparent: whatever JSON value the file carries reaches the consumer verbatim. Display-only:
7332
+ * no gate / policy / trust
7331
7333
  * effect (the trust axis is `contentOrigin` above, which stays a closed table). Before this key existed
7332
7334
  * both legs stripped it (default-strip object); this is the declaration half of the consumer-side fix
7333
7335
  * (ticket B-036 / S-143), the projection half lives in the consumer. */
7334
- source: z.ZodOptional<z.ZodString>;
7336
+ source: z.ZodOptional<z.ZodUnknown>;
7335
7337
  notes: z.ZodOptional<z.ZodString>;
7336
7338
  }, "strip", z.ZodTypeAny, {
7337
7339
  name: string;
@@ -7353,7 +7355,7 @@ export declare const McpServerSpec: z.ZodObject<{
7353
7355
  notes?: string | undefined;
7354
7356
  allowTools?: string[] | undefined;
7355
7357
  contentOrigin?: "local" | "execution" | "external" | undefined;
7356
- source?: string | undefined;
7358
+ source?: unknown;
7357
7359
  }, {
7358
7360
  name: string;
7359
7361
  transport: {
@@ -7374,7 +7376,7 @@ export declare const McpServerSpec: z.ZodObject<{
7374
7376
  allowTools?: string[] | undefined;
7375
7377
  elicitation?: boolean | undefined;
7376
7378
  contentOrigin?: "local" | "execution" | "external" | undefined;
7377
- source?: string | undefined;
7379
+ source?: unknown;
7378
7380
  }>;
7379
7381
  export type McpServerSpec = z.infer<typeof McpServerSpec>;
7380
7382
  export declare const McpConfig: z.ZodEffects<z.ZodObject<{
@@ -7451,16 +7453,18 @@ export declare const McpConfig: z.ZodEffects<z.ZodObject<{
7451
7453
  * consumer can group servers by where they were declared). An OPEN set: CC's `plugin` / `user` /
7452
7454
  * `project` / `local` are conventions, not a vocabulary — a deployment's own word is equally legal, so
7453
7455
  * no closed table here (a closed table would reject the operator's grouping word at parse). ABSENT =
7454
- * no label (`.optional()`, no default — a label has no default tier). 🔴 TYPE-ONLY here (any string):
7455
- * the label RULE (non-empty, ≤80 chars) lives in ONE place — the consumer's projection helper, which
7456
- * drops a malformed label's KEY, keeps the server and records the drop. It deliberately does NOT live
7457
- * here: this domain parses all-or-nothing, so a `min(1)`/`max(80)` at parse would let one empty label
7458
- * default the ENTIRE mcp domain (every server gone) — a blast radius a display label must never have
7459
- * (1.7.0 shipped that shape for a few hours; 1.7.1 retracts it). Display-only: no gate / policy / trust
7456
+ * no label (`.optional()`, no default — a label has no default tier). 🔴 ZERO rules here (`z.unknown()`):
7457
+ * the label RULE (string, non-empty, ≤80 chars) lives in ONE place — the consumer's projection helper,
7458
+ * which drops a malformed label's KEY, keeps the server and records the drop. Nothing may live here:
7459
+ * this domain parses all-or-nothing, so ANY rejection at parse (1.7.0 `min/max`, 1.7.1 `z.string()`
7460
+ * against a `null`) lets one bad label default the ENTIRE mcp domain — every server gone, silently when
7461
+ * no onWarning is wired — a blast radius a display label must never have. 1.7.2 makes the key
7462
+ * parse-transparent: whatever JSON value the file carries reaches the consumer verbatim. Display-only:
7463
+ * no gate / policy / trust
7460
7464
  * effect (the trust axis is `contentOrigin` above, which stays a closed table). Before this key existed
7461
7465
  * both legs stripped it (default-strip object); this is the declaration half of the consumer-side fix
7462
7466
  * (ticket B-036 / S-143), the projection half lives in the consumer. */
7463
- source: z.ZodOptional<z.ZodString>;
7467
+ source: z.ZodOptional<z.ZodUnknown>;
7464
7468
  notes: z.ZodOptional<z.ZodString>;
7465
7469
  }, "strip", z.ZodTypeAny, {
7466
7470
  name: string;
@@ -7482,7 +7486,7 @@ export declare const McpConfig: z.ZodEffects<z.ZodObject<{
7482
7486
  notes?: string | undefined;
7483
7487
  allowTools?: string[] | undefined;
7484
7488
  contentOrigin?: "local" | "execution" | "external" | undefined;
7485
- source?: string | undefined;
7489
+ source?: unknown;
7486
7490
  }, {
7487
7491
  name: string;
7488
7492
  transport: {
@@ -7503,7 +7507,7 @@ export declare const McpConfig: z.ZodEffects<z.ZodObject<{
7503
7507
  allowTools?: string[] | undefined;
7504
7508
  elicitation?: boolean | undefined;
7505
7509
  contentOrigin?: "local" | "execution" | "external" | undefined;
7506
- source?: string | undefined;
7510
+ source?: unknown;
7507
7511
  }>, "many">>;
7508
7512
  }, "strip", z.ZodTypeAny, {
7509
7513
  servers: {
@@ -7526,7 +7530,7 @@ export declare const McpConfig: z.ZodEffects<z.ZodObject<{
7526
7530
  notes?: string | undefined;
7527
7531
  allowTools?: string[] | undefined;
7528
7532
  contentOrigin?: "local" | "execution" | "external" | undefined;
7529
- source?: string | undefined;
7533
+ source?: unknown;
7530
7534
  }[];
7531
7535
  }, {
7532
7536
  servers?: {
@@ -7549,7 +7553,7 @@ export declare const McpConfig: z.ZodEffects<z.ZodObject<{
7549
7553
  allowTools?: string[] | undefined;
7550
7554
  elicitation?: boolean | undefined;
7551
7555
  contentOrigin?: "local" | "execution" | "external" | undefined;
7552
- source?: string | undefined;
7556
+ source?: unknown;
7553
7557
  }[] | undefined;
7554
7558
  }>, {
7555
7559
  servers: {
@@ -7572,7 +7576,7 @@ export declare const McpConfig: z.ZodEffects<z.ZodObject<{
7572
7576
  notes?: string | undefined;
7573
7577
  allowTools?: string[] | undefined;
7574
7578
  contentOrigin?: "local" | "execution" | "external" | undefined;
7575
- source?: string | undefined;
7579
+ source?: unknown;
7576
7580
  }[];
7577
7581
  }, {
7578
7582
  servers?: {
@@ -7595,7 +7599,7 @@ export declare const McpConfig: z.ZodEffects<z.ZodObject<{
7595
7599
  allowTools?: string[] | undefined;
7596
7600
  elicitation?: boolean | undefined;
7597
7601
  contentOrigin?: "local" | "execution" | "external" | undefined;
7598
- source?: string | undefined;
7602
+ source?: unknown;
7599
7603
  }[] | undefined;
7600
7604
  }>;
7601
7605
  export type McpConfig = z.infer<typeof McpConfig>;
@@ -9511,7 +9515,7 @@ export declare const DOMAIN_SCHEMAS: {
9511
9515
  * superRefine);未经 schema 的本地/存量 lane 由消费方 warn 降级(与 activeTierGroup 双层姿势一致)。 */
9512
9516
  default: z.ZodOptional<z.ZodString>;
9513
9517
  /** role → target. Unset roles fall back to `default` (core fallback chain). */
9514
- roles: z.ZodDefault<z.ZodRecord<z.ZodEnum<["default", "summarize", "subagent", "team", "synthesize", "verifier"]>, z.ZodUnion<[z.ZodObject<{
9518
+ roles: z.ZodDefault<z.ZodRecord<z.ZodEnum<["default", "summarize", "subagent", "team", "synthesize", "verifier", "classifier", "consolidate"]>, z.ZodUnion<[z.ZodObject<{
9515
9519
  model: z.ZodString;
9516
9520
  }, "strip", z.ZodTypeAny, {
9517
9521
  model: string;
@@ -9626,7 +9630,7 @@ export declare const DOMAIN_SCHEMAS: {
9626
9630
  extraBody?: Record<string, unknown> | undefined;
9627
9631
  notes?: string | undefined;
9628
9632
  }[];
9629
- roles: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
9633
+ roles: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
9630
9634
  model: string;
9631
9635
  } | {
9632
9636
  select: {
@@ -9683,7 +9687,7 @@ export declare const DOMAIN_SCHEMAS: {
9683
9687
  enabled?: boolean | undefined;
9684
9688
  notes?: string | undefined;
9685
9689
  }[] | undefined;
9686
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
9690
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
9687
9691
  model: string;
9688
9692
  } | {
9689
9693
  select: {
@@ -9738,7 +9742,7 @@ export declare const DOMAIN_SCHEMAS: {
9738
9742
  extraBody?: Record<string, unknown> | undefined;
9739
9743
  notes?: string | undefined;
9740
9744
  }[];
9741
- roles: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
9745
+ roles: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
9742
9746
  model: string;
9743
9747
  } | {
9744
9748
  select: {
@@ -9795,7 +9799,7 @@ export declare const DOMAIN_SCHEMAS: {
9795
9799
  enabled?: boolean | undefined;
9796
9800
  notes?: string | undefined;
9797
9801
  }[] | undefined;
9798
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
9802
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
9799
9803
  model: string;
9800
9804
  } | {
9801
9805
  select: {
@@ -9826,14 +9830,14 @@ export declare const DOMAIN_SCHEMAS: {
9826
9830
  /**
9827
9831
  * 主模型角色标记(0.6.3, E3)——catalog model NAME。worker.model 废除后 service 从 roster
9828
9832
  * 解析 boot 主模型的归宿位:解析语义(resolve-roster)= primary 喂 `default`/`team`/`synthesize` 三角色、
9829
- * cheap 喂 `subagent`/`summarize`(service 现有 ModelRoles 口径;`verifier` 不派生——unset→default 兜底链)。
9833
+ * cheap 喂 `subagent`/`summarize`(service 现有 ModelRoles 口径;`verifier`/`classifier`/`consolidate` 不派生——unset 走 core 兜底链)。
9830
9834
  * 显式 `roles` **逐角色**优先于标记派生;标记优先于全局 models.roles。additive:不设=行为与 0.6.2 全等。
9831
9835
  */
9832
9836
  primaryModel: z.ZodOptional<z.ZodString>;
9833
9837
  /** cheap 模型角色标记(同上;worker.model.cheapId 的迁移归宿,§3②)。 */
9834
9838
  cheapModel: z.ZodOptional<z.ZodString>;
9835
9839
  /** Role map override; unset roles fall back to marker-derived roles, then the global models.roles. */
9836
- roles: z.ZodOptional<z.ZodRecord<z.ZodEnum<["default", "summarize", "subagent", "team", "synthesize", "verifier"]>, z.ZodUnion<[z.ZodObject<{
9840
+ roles: z.ZodOptional<z.ZodRecord<z.ZodEnum<["default", "summarize", "subagent", "team", "synthesize", "verifier", "classifier", "consolidate"]>, z.ZodUnion<[z.ZodObject<{
9837
9841
  model: z.ZodString;
9838
9842
  }, "strip", z.ZodTypeAny, {
9839
9843
  model: string;
@@ -9873,7 +9877,7 @@ export declare const DOMAIN_SCHEMAS: {
9873
9877
  name: string;
9874
9878
  models: string[];
9875
9879
  notes?: string | undefined;
9876
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
9880
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
9877
9881
  model: string;
9878
9882
  } | {
9879
9883
  select: {
@@ -9889,7 +9893,7 @@ export declare const DOMAIN_SCHEMAS: {
9889
9893
  name: string;
9890
9894
  notes?: string | undefined;
9891
9895
  models?: string[] | undefined;
9892
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
9896
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
9893
9897
  model: string;
9894
9898
  } | {
9895
9899
  select: {
@@ -9907,7 +9911,7 @@ export declare const DOMAIN_SCHEMAS: {
9907
9911
  name: string;
9908
9912
  models: string[];
9909
9913
  notes?: string | undefined;
9910
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
9914
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
9911
9915
  model: string;
9912
9916
  } | {
9913
9917
  select: {
@@ -9925,7 +9929,7 @@ export declare const DOMAIN_SCHEMAS: {
9925
9929
  name: string;
9926
9930
  notes?: string | undefined;
9927
9931
  models?: string[] | undefined;
9928
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
9932
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
9929
9933
  model: string;
9930
9934
  } | {
9931
9935
  select: {
@@ -9943,7 +9947,7 @@ export declare const DOMAIN_SCHEMAS: {
9943
9947
  name: string;
9944
9948
  models: string[];
9945
9949
  notes?: string | undefined;
9946
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
9950
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
9947
9951
  model: string;
9948
9952
  } | {
9949
9953
  select: {
@@ -9961,7 +9965,7 @@ export declare const DOMAIN_SCHEMAS: {
9961
9965
  name: string;
9962
9966
  notes?: string | undefined;
9963
9967
  models?: string[] | undefined;
9964
- roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier", {
9968
+ roles?: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
9965
9969
  model: string;
9966
9970
  } | {
9967
9971
  select: {
@@ -10122,16 +10126,18 @@ export declare const DOMAIN_SCHEMAS: {
10122
10126
  * consumer can group servers by where they were declared). An OPEN set: CC's `plugin` / `user` /
10123
10127
  * `project` / `local` are conventions, not a vocabulary — a deployment's own word is equally legal, so
10124
10128
  * no closed table here (a closed table would reject the operator's grouping word at parse). ABSENT =
10125
- * no label (`.optional()`, no default — a label has no default tier). 🔴 TYPE-ONLY here (any string):
10126
- * the label RULE (non-empty, ≤80 chars) lives in ONE place — the consumer's projection helper, which
10127
- * drops a malformed label's KEY, keeps the server and records the drop. It deliberately does NOT live
10128
- * here: this domain parses all-or-nothing, so a `min(1)`/`max(80)` at parse would let one empty label
10129
- * default the ENTIRE mcp domain (every server gone) — a blast radius a display label must never have
10130
- * (1.7.0 shipped that shape for a few hours; 1.7.1 retracts it). Display-only: no gate / policy / trust
10129
+ * no label (`.optional()`, no default — a label has no default tier). 🔴 ZERO rules here (`z.unknown()`):
10130
+ * the label RULE (string, non-empty, ≤80 chars) lives in ONE place — the consumer's projection helper,
10131
+ * which drops a malformed label's KEY, keeps the server and records the drop. Nothing may live here:
10132
+ * this domain parses all-or-nothing, so ANY rejection at parse (1.7.0 `min/max`, 1.7.1 `z.string()`
10133
+ * against a `null`) lets one bad label default the ENTIRE mcp domain — every server gone, silently when
10134
+ * no onWarning is wired — a blast radius a display label must never have. 1.7.2 makes the key
10135
+ * parse-transparent: whatever JSON value the file carries reaches the consumer verbatim. Display-only:
10136
+ * no gate / policy / trust
10131
10137
  * effect (the trust axis is `contentOrigin` above, which stays a closed table). Before this key existed
10132
10138
  * both legs stripped it (default-strip object); this is the declaration half of the consumer-side fix
10133
10139
  * (ticket B-036 / S-143), the projection half lives in the consumer. */
10134
- source: z.ZodOptional<z.ZodString>;
10140
+ source: z.ZodOptional<z.ZodUnknown>;
10135
10141
  notes: z.ZodOptional<z.ZodString>;
10136
10142
  }, "strip", z.ZodTypeAny, {
10137
10143
  name: string;
@@ -10153,7 +10159,7 @@ export declare const DOMAIN_SCHEMAS: {
10153
10159
  notes?: string | undefined;
10154
10160
  allowTools?: string[] | undefined;
10155
10161
  contentOrigin?: "local" | "execution" | "external" | undefined;
10156
- source?: string | undefined;
10162
+ source?: unknown;
10157
10163
  }, {
10158
10164
  name: string;
10159
10165
  transport: {
@@ -10174,7 +10180,7 @@ export declare const DOMAIN_SCHEMAS: {
10174
10180
  allowTools?: string[] | undefined;
10175
10181
  elicitation?: boolean | undefined;
10176
10182
  contentOrigin?: "local" | "execution" | "external" | undefined;
10177
- source?: string | undefined;
10183
+ source?: unknown;
10178
10184
  }>, "many">>;
10179
10185
  }, "strip", z.ZodTypeAny, {
10180
10186
  servers: {
@@ -10197,7 +10203,7 @@ export declare const DOMAIN_SCHEMAS: {
10197
10203
  notes?: string | undefined;
10198
10204
  allowTools?: string[] | undefined;
10199
10205
  contentOrigin?: "local" | "execution" | "external" | undefined;
10200
- source?: string | undefined;
10206
+ source?: unknown;
10201
10207
  }[];
10202
10208
  }, {
10203
10209
  servers?: {
@@ -10220,7 +10226,7 @@ export declare const DOMAIN_SCHEMAS: {
10220
10226
  allowTools?: string[] | undefined;
10221
10227
  elicitation?: boolean | undefined;
10222
10228
  contentOrigin?: "local" | "execution" | "external" | undefined;
10223
- source?: string | undefined;
10229
+ source?: unknown;
10224
10230
  }[] | undefined;
10225
10231
  }>, {
10226
10232
  servers: {
@@ -10243,7 +10249,7 @@ export declare const DOMAIN_SCHEMAS: {
10243
10249
  notes?: string | undefined;
10244
10250
  allowTools?: string[] | undefined;
10245
10251
  contentOrigin?: "local" | "execution" | "external" | undefined;
10246
- source?: string | undefined;
10252
+ source?: unknown;
10247
10253
  }[];
10248
10254
  }, {
10249
10255
  servers?: {
@@ -10266,7 +10272,7 @@ export declare const DOMAIN_SCHEMAS: {
10266
10272
  allowTools?: string[] | undefined;
10267
10273
  elicitation?: boolean | undefined;
10268
10274
  contentOrigin?: "local" | "execution" | "external" | undefined;
10269
- source?: string | undefined;
10275
+ source?: unknown;
10270
10276
  }[] | undefined;
10271
10277
  }>;
10272
10278
  readonly plugins: z.ZodEffects<z.ZodObject<{
package/dist/types.js CHANGED
@@ -368,9 +368,16 @@ export const ModelEntry = z.object({
368
368
  });
369
369
  // `verifier` (2026-06-11, SERVICE-RESPONSE-…-PHASE2): real consumer = core's verification gate
370
370
  // (runWithVerification/resumeWithVerification resolve the verifier sub-task model via this role). Fallback
371
- // semantics per core: a roster that doesn't set `verifier` uses `default`. core also has `advisor` (teacher
372
- // mode) — deliberately NOT added: Service AI evaluated teacher mode and won't consume it (no consumer, no key).
373
- export const ModelRole = z.enum(["default", "summarize", "subagent", "team", "synthesize", "verifier"]);
371
+ // semantics per core: a roster that doesn't set `verifier` uses `default`.
372
+ // 1.8.0(消费方壳侧真案):对齐 core `ModelRole`(9 词)里**有真消费方**的两个缺席角色 ——
373
+ // `classifier` = auto 模式权限分类器(core FALLBACK classifier→summarize→default;tier 缺省 flash);此前 settings
374
+ // 写 `roles.classifier` 被本闭集拒,用户想单独钉分类器模型只能连带 summarize。
375
+ // `consolidate` = 记忆整理(core FALLBACK consolidate→summarize)。
376
+ // 两个词都**不进** roster 标记族(resolve-roster.ts):显式归 cheap 会让 server 把它钉死到 cheapRef,盖掉用户
377
+ // `models.tiers.flash` 的档位与 core 兜底链 —— 新角色「不派生、走 core 兜底、只由 settings 显式钉」。
378
+ // `advisor`(teacher mode)仍 deliberately NOT added: no consumer, no key —— 谁消费谁来加。
379
+ // 子集关系由消费方服务端的型面对账钉(编译期 `satisfies`)钉住(本仓不依赖 core)。
380
+ export const ModelRole = z.enum(["default", "summarize", "subagent", "team", "synthesize", "verifier", "classifier", "consolidate"]);
374
381
  /** A role resolves either to a model NAME, or by capability/price (core 1.25 `{ select }`). */
375
382
  export const RoleTarget = z.union([
376
383
  z.object({ model: z.string().min(1) }),
@@ -474,7 +481,7 @@ export const RosterEntry = z.object({
474
481
  /**
475
482
  * 主模型角色标记(0.6.3, E3)——catalog model NAME。worker.model 废除后 service 从 roster
476
483
  * 解析 boot 主模型的归宿位:解析语义(resolve-roster)= primary 喂 `default`/`team`/`synthesize` 三角色、
477
- * cheap 喂 `subagent`/`summarize`(service 现有 ModelRoles 口径;`verifier` 不派生——unset→default 兜底链)。
484
+ * cheap 喂 `subagent`/`summarize`(service 现有 ModelRoles 口径;`verifier`/`classifier`/`consolidate` 不派生——unset 走 core 兜底链)。
478
485
  * 显式 `roles` **逐角色**优先于标记派生;标记优先于全局 models.roles。additive:不设=行为与 0.6.2 全等。
479
486
  */
480
487
  primaryModel: z.string().min(1).optional(),
@@ -1893,16 +1900,18 @@ export const McpServerSpec = z.object({
1893
1900
  * consumer can group servers by where they were declared). An OPEN set: CC's `plugin` / `user` /
1894
1901
  * `project` / `local` are conventions, not a vocabulary — a deployment's own word is equally legal, so
1895
1902
  * no closed table here (a closed table would reject the operator's grouping word at parse). ABSENT =
1896
- * no label (`.optional()`, no default — a label has no default tier). 🔴 TYPE-ONLY here (any string):
1897
- * the label RULE (non-empty, ≤80 chars) lives in ONE place — the consumer's projection helper, which
1898
- * drops a malformed label's KEY, keeps the server and records the drop. It deliberately does NOT live
1899
- * here: this domain parses all-or-nothing, so a `min(1)`/`max(80)` at parse would let one empty label
1900
- * default the ENTIRE mcp domain (every server gone) — a blast radius a display label must never have
1901
- * (1.7.0 shipped that shape for a few hours; 1.7.1 retracts it). Display-only: no gate / policy / trust
1903
+ * no label (`.optional()`, no default — a label has no default tier). 🔴 ZERO rules here (`z.unknown()`):
1904
+ * the label RULE (string, non-empty, ≤80 chars) lives in ONE place — the consumer's projection helper,
1905
+ * which drops a malformed label's KEY, keeps the server and records the drop. Nothing may live here:
1906
+ * this domain parses all-or-nothing, so ANY rejection at parse (1.7.0 `min/max`, 1.7.1 `z.string()`
1907
+ * against a `null`) lets one bad label default the ENTIRE mcp domain — every server gone, silently when
1908
+ * no onWarning is wired — a blast radius a display label must never have. 1.7.2 makes the key
1909
+ * parse-transparent: whatever JSON value the file carries reaches the consumer verbatim. Display-only:
1910
+ * no gate / policy / trust
1902
1911
  * effect (the trust axis is `contentOrigin` above, which stays a closed table). Before this key existed
1903
1912
  * both legs stripped it (default-strip object); this is the declaration half of the consumer-side fix
1904
1913
  * (ticket B-036 / S-143), the projection half lives in the consumer. */
1905
- source: z.string().optional(),
1914
+ source: z.unknown().optional(),
1906
1915
  notes: z.string().optional(),
1907
1916
  });
1908
1917
  export const McpConfig = z
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/settings-schema",
3
- "version": "1.7.1",
3
+ "version": "1.8.0",
4
4
  "description": "Sema settings schema — pure config contract (zod domains + effective-config + roster resolution + ref-integrity + remoteExec) shared by sema-registry, sema-server, and the TOC desktop/CLI. One source of truth. (Renamed at 1.0.0 from @sema-agent/registry-core — name and docs only, no behavior change; note the range moves 0.19.0 -> 1.0.0, so a dependency must become ^1.0.0. The old names @sema-agent/registry-core <=0.19.0 and @sema-ai/registry-core remain published, frozen, for migration.)",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",