@sema-agent/settings-schema 6.3.0 → 6.4.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 +48 -0
- package/README.md +6 -3
- package/conformance/VERSION +1 -1
- package/conformance/cases/c48-s935-model-headers-transported/expected.json +115 -0
- package/conformance/cases/c48-s935-model-headers-transported/input.json +37 -0
- package/conformance/cases/c48-s935-model-headers-transported/meta.json +6 -0
- package/conformance/cases/c49-s935-model-headers-secret-entry-dropped/expected.json +98 -0
- package/conformance/cases/c49-s935-model-headers-secret-entry-dropped/input.json +28 -0
- package/conformance/cases/c49-s935-model-headers-secret-entry-dropped/meta.json +9 -0
- package/dist/hash.d.ts +3 -3
- package/dist/hash.js +3 -3
- package/dist/hooks.d.ts +8 -8
- package/dist/types.d.ts +52 -1
- package/dist/types.js +40 -13
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,54 @@
|
|
|
8
8
|
|
|
9
9
|
## Unreleased
|
|
10
10
|
|
|
11
|
+
## 6.4.0 — 2026-10-01 — `models.models[].headers` 解析透明键(S-935;与 `compat` 同一只变换)
|
|
12
|
+
|
|
13
|
+
> **判档 = minor**(新键 = additive,README「发版纪律」)。缺席 = 键不铸 = 6.3.0 行为,零迁移;不带 `headers` 的文档读出来逐字节不变
|
|
14
|
+
> (conformance 全语料重加冕:既有 61 条 case、`baseline.json`、`VERSION` 零 diff)。
|
|
15
|
+
|
|
16
|
+
### 病(6.3.0 及更早)
|
|
17
|
+
|
|
18
|
+
sema-server 7.108.0(S-931)给模型目录条目加了 `headers`(部署 ↔ 供应商的 per-model 附加请求头,例 `{"anthropic-beta":"context-1m-2025-08-07"}`
|
|
19
|
+
开 1M 上下文)。本包 `ModelEntry` 没有这个键 ⇒ 每一条按域 schema 解析的读口都把它剥掉并报 `unknown-keys-dropped`
|
|
20
|
+
(实测:`[{"domain":"models","kind":"unknown-keys-dropped","keys":[["models",0,"headers"]]}]`)—— 远端 `readEffectiveWire`、`buildEffective`、
|
|
21
|
+
文件腿 `FileConfigStore.getEffective()`(严格 / `{tolerant:true}` 两形,`loadLocalConfig` 走严格形)、`FileConfigStore.getDomain`
|
|
22
|
+
(`exportBundle` 的读法);写腿 `writeDomainFile` / `validateDomain` 同样剥,且连告警都没有。经生产配置通道写下的 `headers`
|
|
23
|
+
到不了 server 目录,只有绕过读腿的输入(盘上 LKG / 手写 effective)到得了。
|
|
24
|
+
|
|
25
|
+
### 修
|
|
26
|
+
|
|
27
|
+
- `ModelEntry.headers?`(`src/types.ts`):`z.unknown().optional().transform(createFreeFormTransform("headers"))` —— 与 `compat` **同一只**
|
|
28
|
+
变换(本版把 `compat` 那段内联闭包提成包内私有的 `createFreeFormTransform(field)`,两键共用,不再各写一份):缺席不铸键;其余只过
|
|
29
|
+
`vetFreeFormJson` 自由形安全判(密钥形键 / 值、访问器、环、非 JSON、深于 `MAX_EXTRA_BODY_DEPTH`),拒句与 `compat` 逐字同形、只换字段名。
|
|
30
|
+
- **不做形校验**:字符串 / 数组 / 数字 / `null` / 非规范大小写的名(`Anthropic-Beta`)/ 白名单外的名 / 非字符串值 / 写在不读它的线路上,
|
|
31
|
+
本包一律逐字过。头名闭集白名单 × 读它的线路 × 值形的判据**唯一属主是 sema-server**(坏声明 ⇒ 该条目整条不可用),本包复述一份必漂。
|
|
32
|
+
- 登记进 `PARSE_TRANSPARENT_KEYS`(`models[].headers`,`since: "6.4.0"`,`validatedBy: "consumer"`)。`ParseTransparentValidator` 的
|
|
33
|
+
`consumer` 词注去掉了「丢掉坏的那一个键、保留宿主条目」这句处置描述 —— 坏值怎么处置是执法点自己的契约(`headers` 的执法点整条
|
|
34
|
+
条目不可用,`mcp.servers[].source` 的只丢标签),写在各登记行的 `why` 里,本包不替它定(规则少一条,不加新词)。
|
|
35
|
+
- 同深度上限:`src/hash.ts` `MAX_EXTRA_BODY_DEPTH` 注文补 `headers`(与 `extraBody` / `compat` 同一个包裹深度,同一个上限)。
|
|
36
|
+
- 文档:README「Declared-but-unvalidated keys」、`llms.txt` 解析透明键登记表段(4 员 → 5 员)、`llms-full.txt` 补 `headers`。README 同句
|
|
37
|
+
顺手订正:它把 `models[].extraBody` 列成解析透明键、把「the key's own guard」列成第三种校验方 —— 两处都与实现不符(`extraBody`
|
|
38
|
+
有自己的形门,不在登记表里;校验方闭集只有 `engine-ingest` / `consumer` 两词),改成与 `src/types.ts` 一致。
|
|
39
|
+
|
|
40
|
+
### 红先 / 门
|
|
41
|
+
|
|
42
|
+
- `test/model-headers-6.4.0.test.ts` 16 格,修前 15 红 1 绿(绿的是 ③ 负控):① 五条读腿逐字交出、零告警 ①b 写腿逐字落盘
|
|
43
|
+
② 密钥形值 / 键(`sk-ant-…` / 私钥 PEM / `Bearer …` / 密钥形键 / 数组里的嵌套值)拒,拒句 = `compat` 拒句换字段名 ②b 五条读腿上与
|
|
44
|
+
`compat` 同一个处置(经 `buildEffective` 的四条腿逐条丢 `entry-dropped`、兄弟幸存;`getDomain` 整域净化后抛)、零回显
|
|
45
|
+
③ 负控:不带 `headers` 的文档 effective / wire 的 `stableHash` 与 6.3.0 实测金样逐位相同 ④ 不做形校验 ⑤ `stableHash` 键序无关、
|
|
46
|
+
声明 / 换值改变哈希、恰在 `MAX_EXTRA_BODY_DEPTH` 收且包进 effective 可哈希、超一层拒(与 `compat` 同层)⑥ 登记行。
|
|
47
|
+
- 解析透明键登记表门(`test/parse-transparent-keys.test.ts`,从 `DOMAIN_SCHEMAS` 行为派生、双向对拍)随新键自动覆盖。
|
|
48
|
+
- conformance 两条新语料(`npm run conformance:bless` 加冕):`c48-s935-model-headers-transported`(三腿逐字交出、零告警;openai 线路上的
|
|
49
|
+
数组形 `headers` 照样过;无 `headers` 的条目不铸键)、`c49-s935-model-headers-secret-entry-dropped`(密钥形值 ⇒ 条目逐条丢、零回显,
|
|
50
|
+
`secrets` 已登记)。对 6.3.0 源码实测三腿同红(c48:2 处 effective 差 + 1 条多出的 `unknown-keys-dropped`;c49:6 处 effective 差、
|
|
51
|
+
缺 1 条 `entry-dropped`、多 1 条 `unknown-keys-dropped`);`firstRedOn` 留空(historical 阶梯证据真跑于入库之前,不手填,c41 同口径)。
|
|
52
|
+
|
|
53
|
+
### 消费方
|
|
54
|
+
|
|
55
|
+
- **sema-server 7.109.0 提货**:`config-provider.ts` `mapToServiceEffective` 加一行过境 `headers`,并把 `test/catalog-entry-headers.test.ts`
|
|
56
|
+
末段 🚧 S-931-schema 两格(「两条读腿今天剥掉 `headers`」)翻成「读腿逐字交出 `headers`」的正向钉、删该段 🚧。
|
|
57
|
+
- center / TOC:`ModelEntry` 的推断类型多一个 `headers?: unknown`;不读它的消费方零改动。
|
|
58
|
+
|
|
11
59
|
## 6.3.0 — 2026-09-27 — 安全修(codex gpt-6-astra 对 v6.1.0 复审 [high],回填 D-4):可披露身份改白名单闭形 `DISCLOSABLE_IDENTITY_RE` · `redactSecrets` 整串判套在一处归一化上 · 告警坐标出门一道
|
|
12
60
|
|
|
13
61
|
> **判档 = minor**(发版方裁,2026-09-27;原排 6.2.1 当日补丁):按 README「发版纪律」,新导出 `DISCLOSABLE_IDENTITY_RE` = minor
|
package/README.md
CHANGED
|
@@ -209,9 +209,12 @@ therefore shows only `zod`. Node built-ins only (`node:crypto`, `node:fs`).
|
|
|
209
209
|
rule the dropped-entry identity on read warnings already uses: the `DISCLOSABLE_IDENTITY_RE` allowlist ∧ not
|
|
210
210
|
secret-shaped, 6.3.0).
|
|
211
211
|
- **Declared-but-unvalidated keys** (`PARSE_TRANSPARENT_KEYS`, 2.0.0): the ONE registry of keys this package
|
|
212
|
-
carries verbatim WITHOUT checking their shape, each row naming who does check it (the engine's ingest side
|
|
213
|
-
a consumer's
|
|
214
|
-
`mcp.servers[].source` (1.7.2), `mcp.servers[].toolFaces`
|
|
212
|
+
carries verbatim WITHOUT checking their shape, each row naming who does check it (the engine's ingest side or
|
|
213
|
+
a consumer's enforcement point). Today: `models[].compat` (1.10.0), `models[].headers` (6.4.0; the header-name
|
|
214
|
+
allowlist × lane is sema-server's, not restated here), `mcp.servers[].source` (1.7.2), `mcp.servers[].toolFaces`
|
|
215
|
+
(1.9.0), and an entitlement override's `value`. `models[].extraBody` is NOT one of them — it has its own shape
|
|
216
|
+
gate (a plain JSON object); what it leaves open is the key vocabulary inside. `compat` / `headers` / `extraBody`
|
|
217
|
+
still clear the one free-form safety judgment (secret-shaped key/value, accessor, cycle, non-JSON, too deep ⇒ rejected).
|
|
215
218
|
- **Extension namespaces** (`EXTENSION_NAMESPACES`, 1.5.0): keys another writer puts in a domain document by
|
|
216
219
|
contract and this package deliberately does not model (today: the shell's entry-level `sema*` fields on
|
|
217
220
|
`models`). They are still stripped, but they are NOT reported as unknown keys — intent is declared at the
|
package/conformance/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
6.
|
|
1
|
+
6.4.0
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
{
|
|
2
|
+
"domains": {
|
|
3
|
+
"outcome": "effective",
|
|
4
|
+
"effective": {
|
|
5
|
+
"collab": {
|
|
6
|
+
"templates": []
|
|
7
|
+
},
|
|
8
|
+
"entitlement": {
|
|
9
|
+
"budgetGroups": [],
|
|
10
|
+
"groupBindings": [],
|
|
11
|
+
"subjects": [],
|
|
12
|
+
"tiers": []
|
|
13
|
+
},
|
|
14
|
+
"execution": {
|
|
15
|
+
"allowedLanes": [
|
|
16
|
+
"host"
|
|
17
|
+
],
|
|
18
|
+
"required": false
|
|
19
|
+
},
|
|
20
|
+
"governance": {},
|
|
21
|
+
"hosts": {
|
|
22
|
+
"hosts": []
|
|
23
|
+
},
|
|
24
|
+
"limits": {},
|
|
25
|
+
"mcp": {
|
|
26
|
+
"servers": []
|
|
27
|
+
},
|
|
28
|
+
"models": {
|
|
29
|
+
"models": [
|
|
30
|
+
{
|
|
31
|
+
"api": "anthropic-messages",
|
|
32
|
+
"apiKeyEnv": "ANTHROPIC_API_KEY",
|
|
33
|
+
"enabled": true,
|
|
34
|
+
"headers": {
|
|
35
|
+
"anthropic-beta": "context-1m-2025-08-07"
|
|
36
|
+
},
|
|
37
|
+
"id": "claude-x",
|
|
38
|
+
"name": "claude-1m",
|
|
39
|
+
"provider": "anthropic",
|
|
40
|
+
"quotaWeight": 1,
|
|
41
|
+
"reasoning": false,
|
|
42
|
+
"tier": "standard",
|
|
43
|
+
"vision": false
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"api": "openai-completions",
|
|
47
|
+
"apiKeyEnv": "OPENAI_API_KEY",
|
|
48
|
+
"enabled": true,
|
|
49
|
+
"headers": [
|
|
50
|
+
"Anthropic-Beta: not-a-header-bag"
|
|
51
|
+
],
|
|
52
|
+
"id": "gw-id",
|
|
53
|
+
"name": "gw",
|
|
54
|
+
"provider": "openai",
|
|
55
|
+
"quotaWeight": 1,
|
|
56
|
+
"reasoning": false,
|
|
57
|
+
"tier": "standard",
|
|
58
|
+
"vision": false
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"api": "openai-completions",
|
|
62
|
+
"apiKeyEnv": "OPENAI_API_KEY",
|
|
63
|
+
"enabled": true,
|
|
64
|
+
"id": "plain-id",
|
|
65
|
+
"name": "plain",
|
|
66
|
+
"provider": "openai",
|
|
67
|
+
"quotaWeight": 1,
|
|
68
|
+
"reasoning": false,
|
|
69
|
+
"tier": "standard",
|
|
70
|
+
"vision": false
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"roles": {},
|
|
74
|
+
"tierGroups": []
|
|
75
|
+
},
|
|
76
|
+
"plugins": {
|
|
77
|
+
"plugins": []
|
|
78
|
+
},
|
|
79
|
+
"projects": {
|
|
80
|
+
"projects": {}
|
|
81
|
+
},
|
|
82
|
+
"prompts": {
|
|
83
|
+
"bindings": []
|
|
84
|
+
},
|
|
85
|
+
"rosters": {
|
|
86
|
+
"rosters": []
|
|
87
|
+
},
|
|
88
|
+
"runtime": {},
|
|
89
|
+
"scenarios": {
|
|
90
|
+
"scenarios": []
|
|
91
|
+
},
|
|
92
|
+
"skills": {
|
|
93
|
+
"skills": []
|
|
94
|
+
},
|
|
95
|
+
"systems": {
|
|
96
|
+
"systems": []
|
|
97
|
+
},
|
|
98
|
+
"workers": {
|
|
99
|
+
"workers": []
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
"warnings": [],
|
|
103
|
+
"metadata": {
|
|
104
|
+
"version": 7,
|
|
105
|
+
"updatedAt": "2026-10-01T00:00:00.000Z"
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"wire": {
|
|
109
|
+
"derive": true
|
|
110
|
+
},
|
|
111
|
+
"localRoot": {
|
|
112
|
+
"derive": true,
|
|
113
|
+
"localVersion": 1883250445565322
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"version": 7,
|
|
4
|
+
"updatedAt": "2026-10-01T00:00:00.000Z"
|
|
5
|
+
},
|
|
6
|
+
"domains": {
|
|
7
|
+
"models": {
|
|
8
|
+
"models": [
|
|
9
|
+
{
|
|
10
|
+
"name": "claude-1m",
|
|
11
|
+
"provider": "anthropic",
|
|
12
|
+
"api": "anthropic-messages",
|
|
13
|
+
"id": "claude-x",
|
|
14
|
+
"apiKeyEnv": "ANTHROPIC_API_KEY",
|
|
15
|
+
"headers": {
|
|
16
|
+
"anthropic-beta": "context-1m-2025-08-07"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "gw",
|
|
21
|
+
"provider": "openai",
|
|
22
|
+
"id": "gw-id",
|
|
23
|
+
"apiKeyEnv": "OPENAI_API_KEY",
|
|
24
|
+
"headers": [
|
|
25
|
+
"Anthropic-Beta: not-a-header-bag"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "plain",
|
|
30
|
+
"provider": "openai",
|
|
31
|
+
"id": "plain-id",
|
|
32
|
+
"apiKeyEnv": "OPENAI_API_KEY"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contributor": "contract",
|
|
3
|
+
"claim": "S-935(6.4.0):`models[].headers` 是解析透明键(与 `compat` 同一只变换)⇒ 三读腿**逐字交出、零告警**,不剥、不报 `unknown-keys-dropped`;并且本包**不做形校验** —— 写在 openai 线路上的数组形 `headers`(非规范大小写的名、根本不是头袋)照样逐字过,形与线路归 sema-server 的目录条目判据。任一腿把它剥掉,经生产配置通道写下的附加请求头(开 1M 上下文的 `anthropic-beta`)就到不了 server 目录且零告警;任一腿对它做形校验,就是本包复述了 server 的白名单(两个写者)。第三条不带 `headers` 的条目是负控:不铸键。",
|
|
4
|
+
"firstRedOn": [],
|
|
5
|
+
"note": "车SL(2026-10-01)红先:6.3.0 读腿在本条上三腿同红 —— 两条带 `headers` 的条目都被剥掉该键,`unknown-keys-dropped` 点名 `[\"models\",0,\"headers\"]` / `[\"models\",1,\"headers\"]`(实测读数见车SL 收车档)。firstRedOn 为空:`conformance/historical/` 的阶梯证据(2.1.0 及更早)真跑于本条入库之前,没有本条的读数,那一栏只收 historical 真跑,不手填(c41 同口径)。"
|
|
6
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"domains": {
|
|
3
|
+
"outcome": "effective",
|
|
4
|
+
"effective": {
|
|
5
|
+
"collab": {
|
|
6
|
+
"templates": []
|
|
7
|
+
},
|
|
8
|
+
"entitlement": {
|
|
9
|
+
"budgetGroups": [],
|
|
10
|
+
"groupBindings": [],
|
|
11
|
+
"subjects": [],
|
|
12
|
+
"tiers": []
|
|
13
|
+
},
|
|
14
|
+
"execution": {
|
|
15
|
+
"allowedLanes": [
|
|
16
|
+
"host"
|
|
17
|
+
],
|
|
18
|
+
"required": false
|
|
19
|
+
},
|
|
20
|
+
"governance": {},
|
|
21
|
+
"hosts": {
|
|
22
|
+
"hosts": []
|
|
23
|
+
},
|
|
24
|
+
"limits": {},
|
|
25
|
+
"mcp": {
|
|
26
|
+
"servers": []
|
|
27
|
+
},
|
|
28
|
+
"models": {
|
|
29
|
+
"models": [
|
|
30
|
+
{
|
|
31
|
+
"api": "openai-completions",
|
|
32
|
+
"apiKeyEnv": "OPENAI_API_KEY",
|
|
33
|
+
"enabled": true,
|
|
34
|
+
"id": "gw-id",
|
|
35
|
+
"name": "gw",
|
|
36
|
+
"provider": "openai",
|
|
37
|
+
"quotaWeight": 1,
|
|
38
|
+
"reasoning": false,
|
|
39
|
+
"tier": "standard",
|
|
40
|
+
"vision": false
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"roles": {},
|
|
44
|
+
"tierGroups": []
|
|
45
|
+
},
|
|
46
|
+
"plugins": {
|
|
47
|
+
"plugins": []
|
|
48
|
+
},
|
|
49
|
+
"projects": {
|
|
50
|
+
"projects": {}
|
|
51
|
+
},
|
|
52
|
+
"prompts": {
|
|
53
|
+
"bindings": []
|
|
54
|
+
},
|
|
55
|
+
"rosters": {
|
|
56
|
+
"rosters": []
|
|
57
|
+
},
|
|
58
|
+
"runtime": {},
|
|
59
|
+
"scenarios": {
|
|
60
|
+
"scenarios": []
|
|
61
|
+
},
|
|
62
|
+
"skills": {
|
|
63
|
+
"skills": []
|
|
64
|
+
},
|
|
65
|
+
"systems": {
|
|
66
|
+
"systems": []
|
|
67
|
+
},
|
|
68
|
+
"workers": {
|
|
69
|
+
"workers": []
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"warnings": [
|
|
73
|
+
{
|
|
74
|
+
"domain": "models",
|
|
75
|
+
"identity": {
|
|
76
|
+
"id": "claude-x",
|
|
77
|
+
"name": "claude-1m"
|
|
78
|
+
},
|
|
79
|
+
"kind": "entry-dropped",
|
|
80
|
+
"path": [
|
|
81
|
+
"models",
|
|
82
|
+
0
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"metadata": {
|
|
87
|
+
"version": 7,
|
|
88
|
+
"updatedAt": "2026-10-01T00:00:00.000Z"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"wire": {
|
|
92
|
+
"derive": true
|
|
93
|
+
},
|
|
94
|
+
"localRoot": {
|
|
95
|
+
"derive": true,
|
|
96
|
+
"localVersion": 496785931148953
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"version": 7,
|
|
4
|
+
"updatedAt": "2026-10-01T00:00:00.000Z"
|
|
5
|
+
},
|
|
6
|
+
"domains": {
|
|
7
|
+
"models": {
|
|
8
|
+
"models": [
|
|
9
|
+
{
|
|
10
|
+
"name": "claude-1m",
|
|
11
|
+
"provider": "anthropic",
|
|
12
|
+
"api": "anthropic-messages",
|
|
13
|
+
"id": "claude-x",
|
|
14
|
+
"apiKeyEnv": "ANTHROPIC_API_KEY",
|
|
15
|
+
"headers": {
|
|
16
|
+
"x-api-key": "sk-ant-api03-FAKES935CORPUS000000000000000000"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "gw",
|
|
21
|
+
"provider": "openai",
|
|
22
|
+
"id": "gw-id",
|
|
23
|
+
"apiKeyEnv": "OPENAI_API_KEY"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contributor": "contract",
|
|
3
|
+
"claim": "S-935(6.4.0):`models[].headers` 里粘了一把密钥形值(`x-api-key: sk-ant-…`)⇒ 与 `compat` 同一只自由形安全判据拒 ⇒ 该条目**逐条丢**(`entry-dropped`,坐标 `[\"models\",0]`)、兄弟条目幸存、告警面零回显那把钥匙。打的是两种读错:① 腿把 `headers` 当未知键剥掉(6.3.0 形)⇒ 条目带着「看起来干净」的形幸存,明文凭据却已经进了持久层且没人拒;② 腿对 `headers` 另起一套判据(或把拒句拼上值)⇒ 告警面带出密钥。",
|
|
4
|
+
"firstRedOn": [],
|
|
5
|
+
"secrets": [
|
|
6
|
+
"sk-ant-api03-FAKES935CORPUS000000000000000000"
|
|
7
|
+
],
|
|
8
|
+
"note": "车SL(2026-10-01)红先:6.3.0 读腿在本条上三腿同红 —— 条目幸存(`headers` 被剥)+ `unknown-keys-dropped` 点名 `[\"models\",0,\"headers\"]`,没有 `entry-dropped`(实测读数见车SL 收车档)。firstRedOn 为空:同 c48 / c41 口径(historical 阶梯证据真跑于本条入库之前,不手填)。"
|
|
9
|
+
}
|
package/dist/hash.d.ts
CHANGED
|
@@ -23,9 +23,9 @@ export declare const MAX_HASH_WRAPPER_RESERVE = 32;
|
|
|
23
23
|
/** Depth cap for a standalone FREE-FORM config value, reconciled with the hash cap MINUS the wrapper reserve so
|
|
24
24
|
* that ANYTHING the validator accepts is guaranteed hashable in every context it's later hashed in. 168 ≫ any
|
|
25
25
|
* real free-form value (OpenAI-style request params nest <10 deep).
|
|
26
|
-
* Scope: the ONE cap for EVERY free-form field vetted by `vetFreeFormJson` (`ModelEntry.extraBody
|
|
27
|
-
*
|
|
28
|
-
* serves
|
|
26
|
+
* Scope: the ONE cap for EVERY free-form field vetted by `vetFreeFormJson` (`ModelEntry.extraBody`, since 1.10.0
|
|
27
|
+
* `ModelEntry.compat`, since 6.4.0 `ModelEntry.headers`) — they sit at the SAME wrapper depth (`{models:{models:[{…}]}}`),
|
|
28
|
+
* so one cap serves them all. The `EXTRA_BODY` spelling is kept because this is a published export on the `./hash` subpath
|
|
29
29
|
* (renaming it would be a BREAKING change for a purely cosmetic gain). */
|
|
30
30
|
export declare const MAX_EXTRA_BODY_DEPTH: number;
|
|
31
31
|
/** Deterministic JSON with sorted object keys (so key order never affects the hash). */
|
package/dist/hash.js
CHANGED
|
@@ -23,9 +23,9 @@ export const MAX_HASH_WRAPPER_RESERVE = 32;
|
|
|
23
23
|
/** Depth cap for a standalone FREE-FORM config value, reconciled with the hash cap MINUS the wrapper reserve so
|
|
24
24
|
* that ANYTHING the validator accepts is guaranteed hashable in every context it's later hashed in. 168 ≫ any
|
|
25
25
|
* real free-form value (OpenAI-style request params nest <10 deep).
|
|
26
|
-
* Scope: the ONE cap for EVERY free-form field vetted by `vetFreeFormJson` (`ModelEntry.extraBody
|
|
27
|
-
*
|
|
28
|
-
* serves
|
|
26
|
+
* Scope: the ONE cap for EVERY free-form field vetted by `vetFreeFormJson` (`ModelEntry.extraBody`, since 1.10.0
|
|
27
|
+
* `ModelEntry.compat`, since 6.4.0 `ModelEntry.headers`) — they sit at the SAME wrapper depth (`{models:{models:[{…}]}}`),
|
|
28
|
+
* so one cap serves them all. The `EXTRA_BODY` spelling is kept because this is a published export on the `./hash` subpath
|
|
29
29
|
* (renaming it would be a BREAKING change for a purely cosmetic gain). */
|
|
30
30
|
export const MAX_EXTRA_BODY_DEPTH = MAX_HASH_DEPTH - MAX_HASH_WRAPPER_RESERVE;
|
|
31
31
|
/** Deterministic JSON with sorted object keys (so key order never affects the hash). */
|
package/dist/hooks.d.ts
CHANGED
|
@@ -5545,20 +5545,20 @@ export declare const HttpHookEntry: z.ZodObject<{
|
|
|
5545
5545
|
}, "strip", z.ZodTypeAny, {
|
|
5546
5546
|
type: "http";
|
|
5547
5547
|
url: string;
|
|
5548
|
+
headers?: Record<string, string> | undefined;
|
|
5548
5549
|
if?: string | undefined;
|
|
5549
5550
|
timeout?: number | undefined;
|
|
5550
5551
|
statusMessage?: string | undefined;
|
|
5551
5552
|
once?: boolean | undefined;
|
|
5552
|
-
headers?: Record<string, string> | undefined;
|
|
5553
5553
|
allowedEnvVars?: string[] | undefined;
|
|
5554
5554
|
}, {
|
|
5555
5555
|
type: "http";
|
|
5556
5556
|
url: string;
|
|
5557
|
+
headers?: Record<string, string> | undefined;
|
|
5557
5558
|
if?: string | undefined;
|
|
5558
5559
|
timeout?: number | undefined;
|
|
5559
5560
|
statusMessage?: string | undefined;
|
|
5560
5561
|
once?: boolean | undefined;
|
|
5561
|
-
headers?: Record<string, string> | undefined;
|
|
5562
5562
|
allowedEnvVars?: string[] | undefined;
|
|
5563
5563
|
}>;
|
|
5564
5564
|
/** One configured hook (CC settings shape + shell superset fields; discriminated on `type`). */
|
|
@@ -5655,20 +5655,20 @@ export declare const HookEntry: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
|
5655
5655
|
}, "strip", z.ZodTypeAny, {
|
|
5656
5656
|
type: "http";
|
|
5657
5657
|
url: string;
|
|
5658
|
+
headers?: Record<string, string> | undefined;
|
|
5658
5659
|
if?: string | undefined;
|
|
5659
5660
|
timeout?: number | undefined;
|
|
5660
5661
|
statusMessage?: string | undefined;
|
|
5661
5662
|
once?: boolean | undefined;
|
|
5662
|
-
headers?: Record<string, string> | undefined;
|
|
5663
5663
|
allowedEnvVars?: string[] | undefined;
|
|
5664
5664
|
}, {
|
|
5665
5665
|
type: "http";
|
|
5666
5666
|
url: string;
|
|
5667
|
+
headers?: Record<string, string> | undefined;
|
|
5667
5668
|
if?: string | undefined;
|
|
5668
5669
|
timeout?: number | undefined;
|
|
5669
5670
|
statusMessage?: string | undefined;
|
|
5670
5671
|
once?: boolean | undefined;
|
|
5671
|
-
headers?: Record<string, string> | undefined;
|
|
5672
5672
|
allowedEnvVars?: string[] | undefined;
|
|
5673
5673
|
}>]>;
|
|
5674
5674
|
export type HookEntry = z.infer<typeof HookEntry>;
|
|
@@ -5773,20 +5773,20 @@ export declare const HookMatcherEntry: z.ZodObject<{
|
|
|
5773
5773
|
}, "strip", z.ZodTypeAny, {
|
|
5774
5774
|
type: "http";
|
|
5775
5775
|
url: string;
|
|
5776
|
+
headers?: Record<string, string> | undefined;
|
|
5776
5777
|
if?: string | undefined;
|
|
5777
5778
|
timeout?: number | undefined;
|
|
5778
5779
|
statusMessage?: string | undefined;
|
|
5779
5780
|
once?: boolean | undefined;
|
|
5780
|
-
headers?: Record<string, string> | undefined;
|
|
5781
5781
|
allowedEnvVars?: string[] | undefined;
|
|
5782
5782
|
}, {
|
|
5783
5783
|
type: "http";
|
|
5784
5784
|
url: string;
|
|
5785
|
+
headers?: Record<string, string> | undefined;
|
|
5785
5786
|
if?: string | undefined;
|
|
5786
5787
|
timeout?: number | undefined;
|
|
5787
5788
|
statusMessage?: string | undefined;
|
|
5788
5789
|
once?: boolean | undefined;
|
|
5789
|
-
headers?: Record<string, string> | undefined;
|
|
5790
5790
|
allowedEnvVars?: string[] | undefined;
|
|
5791
5791
|
}>]>, "many">;
|
|
5792
5792
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -5819,11 +5819,11 @@ export declare const HookMatcherEntry: z.ZodObject<{
|
|
|
5819
5819
|
} | {
|
|
5820
5820
|
type: "http";
|
|
5821
5821
|
url: string;
|
|
5822
|
+
headers?: Record<string, string> | undefined;
|
|
5822
5823
|
if?: string | undefined;
|
|
5823
5824
|
timeout?: number | undefined;
|
|
5824
5825
|
statusMessage?: string | undefined;
|
|
5825
5826
|
once?: boolean | undefined;
|
|
5826
|
-
headers?: Record<string, string> | undefined;
|
|
5827
5827
|
allowedEnvVars?: string[] | undefined;
|
|
5828
5828
|
})[];
|
|
5829
5829
|
matcher?: string | undefined;
|
|
@@ -5857,11 +5857,11 @@ export declare const HookMatcherEntry: z.ZodObject<{
|
|
|
5857
5857
|
} | {
|
|
5858
5858
|
type: "http";
|
|
5859
5859
|
url: string;
|
|
5860
|
+
headers?: Record<string, string> | undefined;
|
|
5860
5861
|
if?: string | undefined;
|
|
5861
5862
|
timeout?: number | undefined;
|
|
5862
5863
|
statusMessage?: string | undefined;
|
|
5863
5864
|
once?: boolean | undefined;
|
|
5864
|
-
headers?: Record<string, string> | undefined;
|
|
5865
5865
|
allowedEnvVars?: string[] | undefined;
|
|
5866
5866
|
})[];
|
|
5867
5867
|
matcher?: string | undefined;
|
package/dist/types.d.ts
CHANGED
|
@@ -117,7 +117,8 @@ export declare const SealedApiKey: z.ZodObject<{
|
|
|
117
117
|
export type SealedApiKey = z.infer<typeof SealedApiKey>;
|
|
118
118
|
/** 谁来校验一个**解析透明键**的形。闭集:新增一员要在这里加词,穷举消费方即编译红。
|
|
119
119
|
* · `engine-ingest` —— 引擎摄入侧单点校验(不合形的那一条不挂并通告一次);
|
|
120
|
-
* · `consumer` ——
|
|
120
|
+
* · `consumer` —— 消费方的投影/执法点。坏值怎么处置(只丢那一个键 / 整条宿主条目不可用)是那个执法点自己的
|
|
121
|
+
* 契约,写在登记行的 `why` 里 —— 本包不替它定。 */
|
|
121
122
|
export type ParseTransparentValidator = "engine-ingest" | "consumer";
|
|
122
123
|
/** {@link PARSE_TRANSPARENT_KEYS} 的一行。 */
|
|
123
124
|
export interface ParseTransparentKey {
|
|
@@ -247,6 +248,16 @@ export declare const ModelEntry: z.ZodEffects<z.ZodObject<{
|
|
|
247
248
|
* deep to hash later. That is not shape validation — it is the boundary every free-form value must clear to
|
|
248
249
|
* enter the persisted config and `stableHash` (R18). */
|
|
249
250
|
compat: z.ZodEffects<z.ZodOptional<z.ZodUnknown>, unknown, unknown>;
|
|
251
|
+
/** Per-model extra request headers, deployment ↔ provider (e.g. `{"anthropic-beta": "context-1m-2025-08-07"}` on an
|
|
252
|
+
* `anthropic-messages` entry). Real need: a beta that a shell passes as `--betas` / `ANTHROPIC_BETAS` never reaches the
|
|
253
|
+
* request the engine sends; the catalog entry is the deployment-level seat for it — and without this key the entry's
|
|
254
|
+
* declaration is stripped at parse on every read leg, so it never reaches the consumer at all.
|
|
255
|
+
* ABSENT = key not minted = today's behaviour, zero migration.
|
|
256
|
+
*
|
|
257
|
+
* **Parse-transparent** — who validates the shape, and why not here: {@link PARSE_TRANSPARENT_KEYS}
|
|
258
|
+
* (`models.models[].headers`). The ONE rejection that remains is the free-form SAFETY judgment shared with `compat` /
|
|
259
|
+
* `extraBody` ({@link vetFreeFormJson}). */
|
|
260
|
+
headers: z.ZodEffects<z.ZodOptional<z.ZodUnknown>, unknown, unknown>;
|
|
250
261
|
/** 配额倍率(EXPERT-REDESIGN §4-1):该模型烧 token 双窗额度的倍率,默认 1。折算时点=weight-at-burn
|
|
251
262
|
* (记账时固化到 UsageEntry.quotaWeightAtUse/weightedTokens):改倍率只影响此后记账,不回算窗口内历史。 */
|
|
252
263
|
quotaWeight: z.ZodDefault<z.ZodNumber>;
|
|
@@ -283,6 +294,7 @@ export declare const ModelEntry: z.ZodEffects<z.ZodObject<{
|
|
|
283
294
|
} | undefined;
|
|
284
295
|
extraBody?: Record<string, unknown> | undefined;
|
|
285
296
|
compat?: unknown;
|
|
297
|
+
headers?: unknown;
|
|
286
298
|
notes?: string | undefined;
|
|
287
299
|
}, {
|
|
288
300
|
id: string;
|
|
@@ -313,6 +325,7 @@ export declare const ModelEntry: z.ZodEffects<z.ZodObject<{
|
|
|
313
325
|
} | undefined;
|
|
314
326
|
extraBody?: unknown;
|
|
315
327
|
compat?: unknown;
|
|
328
|
+
headers?: unknown;
|
|
316
329
|
quotaWeight?: number | undefined;
|
|
317
330
|
enabled?: boolean | undefined;
|
|
318
331
|
notes?: string | undefined;
|
|
@@ -347,6 +360,7 @@ export declare const ModelEntry: z.ZodEffects<z.ZodObject<{
|
|
|
347
360
|
} | undefined;
|
|
348
361
|
extraBody?: Record<string, unknown> | undefined;
|
|
349
362
|
compat?: unknown;
|
|
363
|
+
headers?: unknown;
|
|
350
364
|
notes?: string | undefined;
|
|
351
365
|
}, {
|
|
352
366
|
id: string;
|
|
@@ -377,6 +391,7 @@ export declare const ModelEntry: z.ZodEffects<z.ZodObject<{
|
|
|
377
391
|
} | undefined;
|
|
378
392
|
extraBody?: unknown;
|
|
379
393
|
compat?: unknown;
|
|
394
|
+
headers?: unknown;
|
|
380
395
|
quotaWeight?: number | undefined;
|
|
381
396
|
enabled?: boolean | undefined;
|
|
382
397
|
notes?: string | undefined;
|
|
@@ -585,6 +600,16 @@ export declare const ModelsConfig: z.ZodEffects<z.ZodObject<{
|
|
|
585
600
|
* deep to hash later. That is not shape validation — it is the boundary every free-form value must clear to
|
|
586
601
|
* enter the persisted config and `stableHash` (R18). */
|
|
587
602
|
compat: z.ZodEffects<z.ZodOptional<z.ZodUnknown>, unknown, unknown>;
|
|
603
|
+
/** Per-model extra request headers, deployment ↔ provider (e.g. `{"anthropic-beta": "context-1m-2025-08-07"}` on an
|
|
604
|
+
* `anthropic-messages` entry). Real need: a beta that a shell passes as `--betas` / `ANTHROPIC_BETAS` never reaches the
|
|
605
|
+
* request the engine sends; the catalog entry is the deployment-level seat for it — and without this key the entry's
|
|
606
|
+
* declaration is stripped at parse on every read leg, so it never reaches the consumer at all.
|
|
607
|
+
* ABSENT = key not minted = today's behaviour, zero migration.
|
|
608
|
+
*
|
|
609
|
+
* **Parse-transparent** — who validates the shape, and why not here: {@link PARSE_TRANSPARENT_KEYS}
|
|
610
|
+
* (`models.models[].headers`). The ONE rejection that remains is the free-form SAFETY judgment shared with `compat` /
|
|
611
|
+
* `extraBody` ({@link vetFreeFormJson}). */
|
|
612
|
+
headers: z.ZodEffects<z.ZodOptional<z.ZodUnknown>, unknown, unknown>;
|
|
588
613
|
/** 配额倍率(EXPERT-REDESIGN §4-1):该模型烧 token 双窗额度的倍率,默认 1。折算时点=weight-at-burn
|
|
589
614
|
* (记账时固化到 UsageEntry.quotaWeightAtUse/weightedTokens):改倍率只影响此后记账,不回算窗口内历史。 */
|
|
590
615
|
quotaWeight: z.ZodDefault<z.ZodNumber>;
|
|
@@ -621,6 +646,7 @@ export declare const ModelsConfig: z.ZodEffects<z.ZodObject<{
|
|
|
621
646
|
} | undefined;
|
|
622
647
|
extraBody?: Record<string, unknown> | undefined;
|
|
623
648
|
compat?: unknown;
|
|
649
|
+
headers?: unknown;
|
|
624
650
|
notes?: string | undefined;
|
|
625
651
|
}, {
|
|
626
652
|
id: string;
|
|
@@ -651,6 +677,7 @@ export declare const ModelsConfig: z.ZodEffects<z.ZodObject<{
|
|
|
651
677
|
} | undefined;
|
|
652
678
|
extraBody?: unknown;
|
|
653
679
|
compat?: unknown;
|
|
680
|
+
headers?: unknown;
|
|
654
681
|
quotaWeight?: number | undefined;
|
|
655
682
|
enabled?: boolean | undefined;
|
|
656
683
|
notes?: string | undefined;
|
|
@@ -685,6 +712,7 @@ export declare const ModelsConfig: z.ZodEffects<z.ZodObject<{
|
|
|
685
712
|
} | undefined;
|
|
686
713
|
extraBody?: Record<string, unknown> | undefined;
|
|
687
714
|
compat?: unknown;
|
|
715
|
+
headers?: unknown;
|
|
688
716
|
notes?: string | undefined;
|
|
689
717
|
}, {
|
|
690
718
|
id: string;
|
|
@@ -715,6 +743,7 @@ export declare const ModelsConfig: z.ZodEffects<z.ZodObject<{
|
|
|
715
743
|
} | undefined;
|
|
716
744
|
extraBody?: unknown;
|
|
717
745
|
compat?: unknown;
|
|
746
|
+
headers?: unknown;
|
|
718
747
|
quotaWeight?: number | undefined;
|
|
719
748
|
enabled?: boolean | undefined;
|
|
720
749
|
notes?: string | undefined;
|
|
@@ -839,6 +868,7 @@ export declare const ModelsConfig: z.ZodEffects<z.ZodObject<{
|
|
|
839
868
|
} | undefined;
|
|
840
869
|
extraBody?: Record<string, unknown> | undefined;
|
|
841
870
|
compat?: unknown;
|
|
871
|
+
headers?: unknown;
|
|
842
872
|
notes?: string | undefined;
|
|
843
873
|
}[];
|
|
844
874
|
roles: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
|
|
@@ -894,6 +924,7 @@ export declare const ModelsConfig: z.ZodEffects<z.ZodObject<{
|
|
|
894
924
|
} | undefined;
|
|
895
925
|
extraBody?: unknown;
|
|
896
926
|
compat?: unknown;
|
|
927
|
+
headers?: unknown;
|
|
897
928
|
quotaWeight?: number | undefined;
|
|
898
929
|
enabled?: boolean | undefined;
|
|
899
930
|
notes?: string | undefined;
|
|
@@ -953,6 +984,7 @@ export declare const ModelsConfig: z.ZodEffects<z.ZodObject<{
|
|
|
953
984
|
} | undefined;
|
|
954
985
|
extraBody?: Record<string, unknown> | undefined;
|
|
955
986
|
compat?: unknown;
|
|
987
|
+
headers?: unknown;
|
|
956
988
|
notes?: string | undefined;
|
|
957
989
|
}[];
|
|
958
990
|
roles: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
|
|
@@ -1008,6 +1040,7 @@ export declare const ModelsConfig: z.ZodEffects<z.ZodObject<{
|
|
|
1008
1040
|
} | undefined;
|
|
1009
1041
|
extraBody?: unknown;
|
|
1010
1042
|
compat?: unknown;
|
|
1043
|
+
headers?: unknown;
|
|
1011
1044
|
quotaWeight?: number | undefined;
|
|
1012
1045
|
enabled?: boolean | undefined;
|
|
1013
1046
|
notes?: string | undefined;
|
|
@@ -9501,6 +9534,16 @@ export declare const DOMAIN_SCHEMAS: {
|
|
|
9501
9534
|
* deep to hash later. That is not shape validation — it is the boundary every free-form value must clear to
|
|
9502
9535
|
* enter the persisted config and `stableHash` (R18). */
|
|
9503
9536
|
compat: z.ZodEffects<z.ZodOptional<z.ZodUnknown>, unknown, unknown>;
|
|
9537
|
+
/** Per-model extra request headers, deployment ↔ provider (e.g. `{"anthropic-beta": "context-1m-2025-08-07"}` on an
|
|
9538
|
+
* `anthropic-messages` entry). Real need: a beta that a shell passes as `--betas` / `ANTHROPIC_BETAS` never reaches the
|
|
9539
|
+
* request the engine sends; the catalog entry is the deployment-level seat for it — and without this key the entry's
|
|
9540
|
+
* declaration is stripped at parse on every read leg, so it never reaches the consumer at all.
|
|
9541
|
+
* ABSENT = key not minted = today's behaviour, zero migration.
|
|
9542
|
+
*
|
|
9543
|
+
* **Parse-transparent** — who validates the shape, and why not here: {@link PARSE_TRANSPARENT_KEYS}
|
|
9544
|
+
* (`models.models[].headers`). The ONE rejection that remains is the free-form SAFETY judgment shared with `compat` /
|
|
9545
|
+
* `extraBody` ({@link vetFreeFormJson}). */
|
|
9546
|
+
headers: z.ZodEffects<z.ZodOptional<z.ZodUnknown>, unknown, unknown>;
|
|
9504
9547
|
/** 配额倍率(EXPERT-REDESIGN §4-1):该模型烧 token 双窗额度的倍率,默认 1。折算时点=weight-at-burn
|
|
9505
9548
|
* (记账时固化到 UsageEntry.quotaWeightAtUse/weightedTokens):改倍率只影响此后记账,不回算窗口内历史。 */
|
|
9506
9549
|
quotaWeight: z.ZodDefault<z.ZodNumber>;
|
|
@@ -9537,6 +9580,7 @@ export declare const DOMAIN_SCHEMAS: {
|
|
|
9537
9580
|
} | undefined;
|
|
9538
9581
|
extraBody?: Record<string, unknown> | undefined;
|
|
9539
9582
|
compat?: unknown;
|
|
9583
|
+
headers?: unknown;
|
|
9540
9584
|
notes?: string | undefined;
|
|
9541
9585
|
}, {
|
|
9542
9586
|
id: string;
|
|
@@ -9567,6 +9611,7 @@ export declare const DOMAIN_SCHEMAS: {
|
|
|
9567
9611
|
} | undefined;
|
|
9568
9612
|
extraBody?: unknown;
|
|
9569
9613
|
compat?: unknown;
|
|
9614
|
+
headers?: unknown;
|
|
9570
9615
|
quotaWeight?: number | undefined;
|
|
9571
9616
|
enabled?: boolean | undefined;
|
|
9572
9617
|
notes?: string | undefined;
|
|
@@ -9601,6 +9646,7 @@ export declare const DOMAIN_SCHEMAS: {
|
|
|
9601
9646
|
} | undefined;
|
|
9602
9647
|
extraBody?: Record<string, unknown> | undefined;
|
|
9603
9648
|
compat?: unknown;
|
|
9649
|
+
headers?: unknown;
|
|
9604
9650
|
notes?: string | undefined;
|
|
9605
9651
|
}, {
|
|
9606
9652
|
id: string;
|
|
@@ -9631,6 +9677,7 @@ export declare const DOMAIN_SCHEMAS: {
|
|
|
9631
9677
|
} | undefined;
|
|
9632
9678
|
extraBody?: unknown;
|
|
9633
9679
|
compat?: unknown;
|
|
9680
|
+
headers?: unknown;
|
|
9634
9681
|
quotaWeight?: number | undefined;
|
|
9635
9682
|
enabled?: boolean | undefined;
|
|
9636
9683
|
notes?: string | undefined;
|
|
@@ -9755,6 +9802,7 @@ export declare const DOMAIN_SCHEMAS: {
|
|
|
9755
9802
|
} | undefined;
|
|
9756
9803
|
extraBody?: Record<string, unknown> | undefined;
|
|
9757
9804
|
compat?: unknown;
|
|
9805
|
+
headers?: unknown;
|
|
9758
9806
|
notes?: string | undefined;
|
|
9759
9807
|
}[];
|
|
9760
9808
|
roles: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
|
|
@@ -9810,6 +9858,7 @@ export declare const DOMAIN_SCHEMAS: {
|
|
|
9810
9858
|
} | undefined;
|
|
9811
9859
|
extraBody?: unknown;
|
|
9812
9860
|
compat?: unknown;
|
|
9861
|
+
headers?: unknown;
|
|
9813
9862
|
quotaWeight?: number | undefined;
|
|
9814
9863
|
enabled?: boolean | undefined;
|
|
9815
9864
|
notes?: string | undefined;
|
|
@@ -9869,6 +9918,7 @@ export declare const DOMAIN_SCHEMAS: {
|
|
|
9869
9918
|
} | undefined;
|
|
9870
9919
|
extraBody?: Record<string, unknown> | undefined;
|
|
9871
9920
|
compat?: unknown;
|
|
9921
|
+
headers?: unknown;
|
|
9872
9922
|
notes?: string | undefined;
|
|
9873
9923
|
}[];
|
|
9874
9924
|
roles: Partial<Record<"default" | "summarize" | "subagent" | "team" | "synthesize" | "verifier" | "classifier" | "consolidate", {
|
|
@@ -9924,6 +9974,7 @@ export declare const DOMAIN_SCHEMAS: {
|
|
|
9924
9974
|
} | undefined;
|
|
9925
9975
|
extraBody?: unknown;
|
|
9926
9976
|
compat?: unknown;
|
|
9977
|
+
headers?: unknown;
|
|
9927
9978
|
quotaWeight?: number | undefined;
|
|
9928
9979
|
enabled?: boolean | undefined;
|
|
9929
9980
|
notes?: string | undefined;
|
package/dist/types.js
CHANGED
|
@@ -201,9 +201,9 @@ export function extraBodyUnsafe(v) {
|
|
|
201
201
|
}
|
|
202
202
|
return false;
|
|
203
203
|
}
|
|
204
|
-
/** THE vetting pipeline for every FREE-FORM JSON value that lands in the persisted config — `ModelEntry.extraBody
|
|
205
|
-
* and `ModelEntry.
|
|
206
|
-
* free-form field would have copied it). The judgment is identical for every such field, so it lives in one place:
|
|
204
|
+
/** THE vetting pipeline for every FREE-FORM JSON value that lands in the persisted config — `ModelEntry.extraBody`,
|
|
205
|
+
* `ModelEntry.compat` and `ModelEntry.headers` share this ONE function (1.10.0; before that it was inline in `extraBody`
|
|
206
|
+
* and a second free-form field would have copied it). The judgment is identical for every such field, so it lives in one place:
|
|
207
207
|
*
|
|
208
208
|
* 1. getter-free descriptor walk ({@link extraBodyUnsafe}) over the RAW value — never invokes a getter, and any
|
|
209
209
|
* reflective throw (a hostile Proxy trap could throw a secret-bearing message) collapses into a FIXED message;
|
|
@@ -234,6 +234,22 @@ function vetFreeFormJson(v, field) {
|
|
|
234
234
|
return { ok: false, message: `${field}: its serialized form carries a secret` };
|
|
235
235
|
return { ok: true, value: clone };
|
|
236
236
|
}
|
|
237
|
+
/** The transform of every **parse-transparent free-form** key (`z.unknown().optional().transform(createFreeFormTransform(field))`:
|
|
238
|
+
* `ModelEntry.compat` / `ModelEntry.headers`) — ONE closure, so those keys cannot drift apart: absent stays absent (key not
|
|
239
|
+
* minted); anything else is the {@link vetFreeFormJson} safety judgment and nothing more (no SHAPE rule — whose job that is,
|
|
240
|
+
* per key, is {@link PARSE_TRANSPARENT_KEYS}). `extraBody` is not one of these: it has its own shape gate first. */
|
|
241
|
+
function createFreeFormTransform(field) {
|
|
242
|
+
return (v, ctx) => {
|
|
243
|
+
if (v === undefined)
|
|
244
|
+
return undefined;
|
|
245
|
+
const vetted = vetFreeFormJson(v, field);
|
|
246
|
+
if (!vetted.ok) {
|
|
247
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, message: vetted.message });
|
|
248
|
+
return z.NEVER;
|
|
249
|
+
}
|
|
250
|
+
return vetted.value;
|
|
251
|
+
};
|
|
252
|
+
}
|
|
237
253
|
/** A k8s resource quantity ("250m", "1", "0.5", "512Mi", "1Gi", "128M") — catches garbage at config-submit
|
|
238
254
|
* rather than surfacing as a reconcile ApplyError at the apiserver (consistent with ENV_NAME/DURATION guards). */
|
|
239
255
|
export const K8S_QUANTITY = z.string().regex(/^\d+(\.\d+)?(m|[kKMGTPE]i?)?$/, 'must be a k8s quantity like "250m", "512Mi", "1Gi"');
|
|
@@ -313,6 +329,13 @@ export const PARSE_TRANSPARENT_KEYS = [
|
|
|
313
329
|
validatedBy: "engine-ingest",
|
|
314
330
|
why: "镜像引擎的 per-model wire-compat 声明(thinkingFormat 等五键);那张词表随引擎走,本包复述一份必漂。",
|
|
315
331
|
},
|
|
332
|
+
{
|
|
333
|
+
domain: "models",
|
|
334
|
+
path: "models[].headers",
|
|
335
|
+
since: "6.4.0",
|
|
336
|
+
validatedBy: "consumer",
|
|
337
|
+
why: "部署 ↔ 供应商的 per-model 附加请求头;判据(头名闭集白名单 × 读它的线路 × 值形)的唯一属主是 server 的目录条目判据(坏声明 ⇒ 该条目整条不可用,不是丢头照常),本包复述一份那张表必漂、两处各一份就是两个写者。",
|
|
338
|
+
},
|
|
316
339
|
{
|
|
317
340
|
domain: "mcp",
|
|
318
341
|
path: "servers[].source",
|
|
@@ -424,16 +447,20 @@ export const ModelEntry = z.object({
|
|
|
424
447
|
compat: z
|
|
425
448
|
.unknown()
|
|
426
449
|
.optional()
|
|
427
|
-
.transform((
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
450
|
+
.transform(createFreeFormTransform("compat")),
|
|
451
|
+
/** Per-model extra request headers, deployment ↔ provider (e.g. `{"anthropic-beta": "context-1m-2025-08-07"}` on an
|
|
452
|
+
* `anthropic-messages` entry). Real need: a beta that a shell passes as `--betas` / `ANTHROPIC_BETAS` never reaches the
|
|
453
|
+
* request the engine sends; the catalog entry is the deployment-level seat for it — and without this key the entry's
|
|
454
|
+
* declaration is stripped at parse on every read leg, so it never reaches the consumer at all.
|
|
455
|
+
* ABSENT = key not minted = today's behaviour, zero migration.
|
|
456
|
+
*
|
|
457
|
+
* **Parse-transparent** — who validates the shape, and why not here: {@link PARSE_TRANSPARENT_KEYS}
|
|
458
|
+
* (`models.models[].headers`). The ONE rejection that remains is the free-form SAFETY judgment shared with `compat` /
|
|
459
|
+
* `extraBody` ({@link vetFreeFormJson}). */
|
|
460
|
+
headers: z
|
|
461
|
+
.unknown()
|
|
462
|
+
.optional()
|
|
463
|
+
.transform(createFreeFormTransform("headers")),
|
|
437
464
|
/** 配额倍率(EXPERT-REDESIGN §4-1):该模型烧 token 双窗额度的倍率,默认 1。折算时点=weight-at-burn
|
|
438
465
|
* (记账时固化到 UsageEntry.quotaWeightAtUse/weightedTokens):改倍率只影响此后记账,不回算窗口内历史。 */
|
|
439
466
|
quotaWeight: z.number().finite().nonnegative().default(1),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/settings-schema",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.4.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",
|