@sema-agent/server 7.130.0 → 7.132.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.
Files changed (294) hide show
  1. package/MIGRATION.md +396 -0
  2. package/README.md +13 -6
  3. package/README.zh-CN.md +9 -5
  4. package/USAGE.md +187 -50
  5. package/dist/approval-card.d.ts +3 -1
  6. package/dist/approval-card.js +2 -3
  7. package/dist/audit.d.ts +7 -10
  8. package/dist/audit.js +4 -1
  9. package/dist/auth-bridge.d.ts +4 -0
  10. package/dist/auth-bridge.js +10 -11
  11. package/dist/bench/s1/live-deps.js +2 -0
  12. package/dist/boot/deployment-mods.d.ts +31 -0
  13. package/dist/boot/deployment-mods.js +26 -0
  14. package/dist/boot/execution-env.d.ts +1 -1
  15. package/dist/boot/execution-env.js +19 -6
  16. package/dist/boot/memory-boundary.d.ts +2 -2
  17. package/dist/boot/read-deny-anchor-audit.d.ts +17 -0
  18. package/dist/boot/read-deny-anchor-audit.js +36 -0
  19. package/dist/boot/resolve-spec.d.ts +1 -5
  20. package/dist/boot/resolve-spec.js +56 -61
  21. package/dist/boot/runner-deps.d.ts +19 -8
  22. package/dist/boot/runner-deps.js +14 -2
  23. package/dist/boot/session-faces.d.ts +1 -7
  24. package/dist/boot/stage-02-web-admin-pull.js +9 -1
  25. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  26. package/dist/boot/stage-03-store-backend.js +2 -2
  27. package/dist/boot/stage-04-stores.d.ts +1 -1
  28. package/dist/boot/stage-05-execution-env.d.ts +4 -4
  29. package/dist/boot/stage-05-execution-env.js +7 -10
  30. package/dist/boot/stage-06-runners.d.ts +2 -2
  31. package/dist/boot/stage-06-runners.js +5 -4
  32. package/dist/boot/stage-07-capability-layer.d.ts +2 -2
  33. package/dist/boot/stage-07-capability-layer.js +3 -3
  34. package/dist/boot/stage-08-reapers.d.ts +2 -2
  35. package/dist/boot/stage-09-leader.d.ts +3 -9
  36. package/dist/boot/stage-10-http-server.d.ts +3 -9
  37. package/dist/boot/stage-10-http-server.js +12 -10
  38. package/dist/boot/stores.d.ts +1 -1
  39. package/dist/boot/stores.js +5 -6
  40. package/dist/boot/web-admin.d.ts +0 -3
  41. package/dist/boot/web-admin.js +35 -35
  42. package/dist/brain.js +17 -22
  43. package/dist/budget.js +5 -4
  44. package/dist/caller-text-echo.d.ts +20 -0
  45. package/dist/caller-text-echo.js +24 -0
  46. package/dist/capabilities/brand-identity.d.ts +26 -0
  47. package/dist/capabilities/brand-identity.js +27 -0
  48. package/dist/capabilities/builtin-tools.js +2 -1
  49. package/dist/capabilities/center-plugins.js +1 -1
  50. package/dist/capabilities/center-prompts.d.ts +32 -59
  51. package/dist/capabilities/center-prompts.js +18 -32
  52. package/dist/capabilities/composite-members.d.ts +1 -0
  53. package/dist/capabilities/composite-members.js +1 -0
  54. package/dist/capabilities/engine-capabilities.js +2 -1
  55. package/dist/capabilities/hands-lane.d.ts +9 -6
  56. package/dist/capabilities/hands-lane.js +3 -3
  57. package/dist/capabilities/host-tool-names.d.ts +17 -0
  58. package/dist/capabilities/host-tool-names.js +15 -0
  59. package/dist/capabilities/mcp-probe.d.ts +14 -1
  60. package/dist/capabilities/mcp-probe.js +22 -133
  61. package/dist/capabilities/repo-tools.js +4 -3
  62. package/dist/capabilities/scenarios.d.ts +42 -47
  63. package/dist/capabilities/scenarios.js +19 -35
  64. package/dist/capabilities/select-environment-tool.js +2 -1
  65. package/dist/capabilities/send-user-file-tool.d.ts +0 -1
  66. package/dist/capabilities/send-user-file-tool.js +2 -2
  67. package/dist/capabilities/skills.d.ts +19 -4
  68. package/dist/capabilities/skills.js +30 -10
  69. package/dist/capabilities/tool-defer.js +2 -1
  70. package/dist/config-catalog.js +22 -11
  71. package/dist/config-invariants.js +2 -2
  72. package/dist/config-lkg.d.ts +9 -9
  73. package/dist/config-lkg.js +20 -4
  74. package/dist/config-provider.d.ts +3 -1
  75. package/dist/config-provider.js +14 -6
  76. package/dist/config-types.d.ts +13 -9
  77. package/dist/config.d.ts +2 -2
  78. package/dist/config.js +34 -20
  79. package/dist/device-ws-protocol.d.ts +1 -1
  80. package/dist/device-ws-protocol.js +1 -0
  81. package/dist/elicitation.d.ts +7 -0
  82. package/dist/elicitation.js +20 -5
  83. package/dist/env-name-allowlist-knobs.d.ts +12 -2
  84. package/dist/env-name-allowlist-knobs.js +5 -4
  85. package/dist/exec-bounds.d.ts +15 -3
  86. package/dist/exec-bounds.js +4 -0
  87. package/dist/execution-lane-caps.d.ts +9 -2
  88. package/dist/execution-lane-caps.js +11 -0
  89. package/dist/hooks/classic-stations.d.ts +86 -0
  90. package/dist/hooks/classic-stations.js +27 -0
  91. package/dist/hooks/hook-llm.d.ts +8 -5
  92. package/dist/hooks/hook-llm.js +80 -37
  93. package/dist/hooks/hook-runner.d.ts +273 -75
  94. package/dist/hooks/hook-runner.js +293 -317
  95. package/dist/http/admission.d.ts +8 -2
  96. package/dist/http/admission.js +103 -59
  97. package/dist/http/approval-sweeps.js +59 -18
  98. package/dist/http/checkpoint-ctx.d.ts +36 -18
  99. package/dist/http/checkpoint-ctx.js +14 -10
  100. package/dist/http/claimed-run.d.ts +13 -0
  101. package/dist/http/claimed-run.js +15 -0
  102. package/dist/http/device-placement.js +5 -10
  103. package/dist/http/dispatch.d.ts +0 -4
  104. package/dist/http/dispatch.js +6 -10
  105. package/dist/http/durable-run-leg.d.ts +2 -1
  106. package/dist/http/durable-run-leg.js +5 -3
  107. package/dist/http/health-self-report.d.ts +7 -5
  108. package/dist/http/health-self-report.js +4 -18
  109. package/dist/http/principal-gate.d.ts +23 -6
  110. package/dist/http/principal-gate.js +24 -5
  111. package/dist/http/refusal-body.d.ts +21 -0
  112. package/dist/http/refusal-body.js +4 -0
  113. package/dist/http/request-guards.d.ts +27 -0
  114. package/dist/http/request-guards.js +24 -3
  115. package/dist/http/resume-legs.d.ts +25 -0
  116. package/dist/http/resume-legs.js +48 -26
  117. package/dist/http/routes/approvals-assistant.js +1 -1
  118. package/dist/http/routes/capabilities.js +7 -17
  119. package/dist/http/routes/diagnostics.js +1 -1
  120. package/dist/http/routes/rules.js +2 -2
  121. package/dist/http/routes/runs.js +13 -17
  122. package/dist/http/routes/session-sync.js +4 -2
  123. package/dist/http/routes/sessions.js +23 -11
  124. package/dist/http/routes/shared-memory.js +2 -13
  125. package/dist/http/routes/side-query.js +2 -3
  126. package/dist/http/routes/tasks.js +34 -19
  127. package/dist/http/scenario-read-face.d.ts +14 -0
  128. package/dist/http/scenario-read-face.js +5 -0
  129. package/dist/http/send.d.ts +13 -1
  130. package/dist/http/send.js +12 -1
  131. package/dist/http/server.d.ts +37 -23
  132. package/dist/http/server.js +30 -4
  133. package/dist/http/stored-body-replay.d.ts +10 -3
  134. package/dist/http/stored-body-replay.js +27 -6
  135. package/dist/http/submit-ctx.d.ts +25 -0
  136. package/dist/http/submit-ctx.js +39 -0
  137. package/dist/http/wire-types.d.ts +18 -5
  138. package/dist/index.d.ts +3 -2
  139. package/dist/index.js +3 -2
  140. package/dist/lane-home-probe.d.ts +43 -0
  141. package/dist/lane-home-probe.js +35 -0
  142. package/dist/limit-refusal.d.ts +47 -0
  143. package/dist/limit-refusal.js +12 -0
  144. package/dist/main.js +1 -1
  145. package/dist/mcp-assertion-header.d.ts +3 -11
  146. package/dist/mcp-assertion-header.js +3 -9
  147. package/dist/mcp-tool-faces.d.ts +5 -0
  148. package/dist/mcp-tool-faces.js +5 -1
  149. package/dist/memory-scope.d.ts +1 -1
  150. package/dist/model-entry-refusal.d.ts +1 -7
  151. package/dist/model-provider.d.ts +39 -12
  152. package/dist/model-provider.js +19 -2
  153. package/dist/model-route-endpoint.d.ts +52 -12
  154. package/dist/model-route-endpoint.js +48 -26
  155. package/dist/model-route-gap.d.ts +5 -4
  156. package/dist/model-route-gap.js +1 -1
  157. package/dist/model-select.d.ts +58 -0
  158. package/dist/model-select.js +31 -0
  159. package/dist/namespaced-rule-name.d.ts +7 -4
  160. package/dist/namespaced-rule-name.js +4 -3
  161. package/dist/observability/cost-taxonomy.d.ts +7 -7
  162. package/dist/observability/fail-open.d.ts +53 -12
  163. package/dist/observability/fail-open.js +47 -7
  164. package/dist/observability/metrics.js +3 -1
  165. package/dist/observability/prompt-manifest.d.ts +47 -82
  166. package/dist/observability/prompt-manifest.js +119 -17
  167. package/dist/observability/run-terminal.js +14 -6
  168. package/dist/observability/secret-env-scrub.d.ts +13 -1
  169. package/dist/observability/secret-env-scrub.js +13 -1
  170. package/dist/observability/tool-trace.d.ts +16 -21
  171. package/dist/observability/tool-trace.js +51 -42
  172. package/dist/per-task-image.d.ts +7 -1
  173. package/dist/per-task-image.js +3 -3
  174. package/dist/plain-string-record.d.ts +25 -0
  175. package/dist/plain-string-record.js +32 -0
  176. package/dist/plugins/blob-backend.d.ts +68 -13
  177. package/dist/plugins/blob-backend.js +53 -10
  178. package/dist/plugins/checkpoint-store-sql.d.ts +14 -4
  179. package/dist/plugins/checkpoint-store-sql.js +39 -26
  180. package/dist/plugins/k8s-bg-scripts.d.ts +11 -0
  181. package/dist/plugins/k8s-bg-scripts.js +22 -0
  182. package/dist/plugins/local-checkpoint-store.js +5 -2
  183. package/dist/plugins/local-session-store.js +3 -3
  184. package/dist/plugins/one-time-migrations.d.ts +147 -91
  185. package/dist/plugins/one-time-migrations.js +372 -208
  186. package/dist/plugins/permission-rule-store-sql.d.ts +13 -7
  187. package/dist/plugins/permission-rule-store-sql.js +4 -18
  188. package/dist/plugins/pg-session-storage.d.ts +4 -5
  189. package/dist/plugins/pg-session-storage.js +7 -17
  190. package/dist/plugins/remote-env-adb.d.ts +6 -0
  191. package/dist/plugins/remote-env-adb.js +9 -4
  192. package/dist/plugins/remote-env-device.js +3 -0
  193. package/dist/plugins/remote-env-e2b.d.ts +1 -1
  194. package/dist/plugins/remote-env-e2b.js +21 -9
  195. package/dist/plugins/remote-env-host.d.ts +9 -9
  196. package/dist/plugins/remote-env-host.js +10 -32
  197. package/dist/plugins/remote-env-k8s.d.ts +95 -26
  198. package/dist/plugins/remote-env-k8s.js +265 -90
  199. package/dist/plugins/remote-env-local-docker.d.ts +20 -1
  200. package/dist/plugins/remote-env-local-docker.js +77 -9
  201. package/dist/plugins/remote-env-ssh.d.ts +15 -0
  202. package/dist/plugins/remote-env-ssh.js +109 -3
  203. package/dist/plugins/remote-shell.d.ts +0 -1
  204. package/dist/plugins/remote-shell.js +1 -2
  205. package/dist/plugins/retention-store-sql.js +6 -2
  206. package/dist/plugins/schema-consistency.d.ts +54 -0
  207. package/dist/plugins/schema-consistency.js +52 -0
  208. package/dist/plugins/session-epoch-anchor.d.ts +13 -0
  209. package/dist/plugins/session-epoch-anchor.js +23 -0
  210. package/dist/plugins/shared-memory-store-sql.d.ts +9 -3
  211. package/dist/plugins/shared-memory-store-sql.js +5 -16
  212. package/dist/plugins/sql-driver.d.ts +141 -0
  213. package/dist/plugins/sql-driver.js +115 -1
  214. package/dist/plugins/sql-errors.d.ts +41 -0
  215. package/dist/plugins/sql-errors.js +36 -0
  216. package/dist/plugins/store-backend.js +2 -1
  217. package/dist/plugins/tidb-session-storage.d.ts +7 -11
  218. package/dist/plugins/tidb-session-storage.js +6 -16
  219. package/dist/plugins/tidb-session-store.js +1 -1
  220. package/dist/prompts-domain-validate.d.ts +17 -61
  221. package/dist/prompts-domain-validate.js +9 -119
  222. package/dist/question.d.ts +18 -9
  223. package/dist/question.js +21 -13
  224. package/dist/request-key-closure.d.ts +4 -4
  225. package/dist/request-key-closure.js +18 -13
  226. package/dist/rule-entry-list.d.ts +134 -24
  227. package/dist/rule-entry-list.js +162 -30
  228. package/dist/run-local.d.ts +3 -3
  229. package/dist/run-local.js +26 -25
  230. package/dist/runs.d.ts +48 -2
  231. package/dist/runs.js +61 -2
  232. package/dist/server-secret-env.d.ts +44 -18
  233. package/dist/server-secret-env.js +49 -8
  234. package/dist/session-incarnation.d.ts +15 -5
  235. package/dist/session-incarnation.js +16 -9
  236. package/dist/session-titler.js +12 -2
  237. package/dist/spec-fields.d.ts +34 -18
  238. package/dist/spec-fields.js +46 -53
  239. package/dist/sql-engine-posture.d.ts +29 -4
  240. package/dist/sql-engine-posture.js +36 -1
  241. package/dist/stored-request-hooks-m20.d.ts +23 -0
  242. package/dist/stored-request-hooks-m20.js +124 -0
  243. package/dist/stored-request-tool-axes-m19.d.ts +20 -5
  244. package/dist/stored-request-tool-axes-m19.js +30 -2
  245. package/dist/task-a2a.d.ts +9 -1
  246. package/dist/task-a2a.js +73 -47
  247. package/dist/task-mcp.d.ts +54 -102
  248. package/dist/task-mcp.js +194 -92
  249. package/dist/task-settings.d.ts +47 -25
  250. package/dist/task-settings.js +46 -61
  251. package/dist/text-bidi.d.ts +3 -46
  252. package/dist/text-bidi.js +3 -3
  253. package/dist/tool-approval.d.ts +1 -1
  254. package/dist/trace/core-keyset-guard.d.ts +24 -4
  255. package/dist/trace/engine-notice-wire.d.ts +11 -3
  256. package/dist/trace/engine-notice-wire.js +8 -1
  257. package/dist/trace/ledger-events.d.ts +3 -1
  258. package/dist/trace/ledger-sink.d.ts +29 -0
  259. package/dist/trace/ledger-sink.js +15 -1
  260. package/dist/trace/model-segment.js +1 -1
  261. package/dist/trace/project.d.ts +25 -6
  262. package/dist/trace/project.js +68 -22
  263. package/dist/trace/wire-projection-faces.d.ts +80 -2
  264. package/dist/trace/wire-projection-faces.js +23 -1
  265. package/dist/user-authored-text.d.ts +7 -0
  266. package/dist/user-authored-text.js +3 -0
  267. package/dist/web-admin-client/apply-effective.js +10 -5
  268. package/dist/web-admin-client/candidate-gate.d.ts +6 -6
  269. package/dist/web-admin-client/candidate-gate.js +3 -3
  270. package/dist/web-admin-client/http-client.js +0 -6
  271. package/dist/web-admin-client/read-warnings.d.ts +13 -0
  272. package/dist/web-admin-client/read-warnings.js +10 -0
  273. package/dist/web-admin-client/skills-mcp.d.ts +3 -0
  274. package/dist/web-admin-client/skills-mcp.js +9 -6
  275. package/dist/web-admin-client/types.d.ts +3 -4
  276. package/dist/workspace-cache.d.ts +35 -0
  277. package/dist/workspace-cache.js +36 -0
  278. package/dist/workspace-space.d.ts +3 -2
  279. package/dist/workspace-space.js +2 -0
  280. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +8 -1
  281. package/package.json +4 -4
  282. package/scripts/drain-check-local.mjs +37 -3
  283. package/scripts/drain-check.mysql.sql +30 -2
  284. package/scripts/drain-check.pg.sql +29 -2
  285. package/dist/capabilities/memory-notice.d.ts +0 -138
  286. package/dist/capabilities/memory-notice.js +0 -64
  287. package/dist/capabilities/prompt.d.ts +0 -17
  288. package/dist/capabilities/prompt.js +0 -6
  289. package/dist/mcp-content-origin.d.ts +0 -34
  290. package/dist/mcp-content-origin.js +0 -10
  291. package/dist/tool-axis-words.d.ts +0 -27
  292. package/dist/tool-axis-words.js +0 -9
  293. package/dist/wire-name-bound.d.ts +0 -14
  294. package/dist/wire-name-bound.js +0 -13
@@ -1,6 +1,7 @@
1
1
  import { readdirSync, readFileSync, realpathSync, statSync } from "node:fs";
2
2
  import { join, resolve, sep } from "node:path";
3
3
  import { toolsRunOnThisHost } from "../task-cwd.js";
4
+ import { createLogger } from "../observability/logger.js";
4
5
  export function assertConfined(p, rootReal, label = "skill entry") {
5
6
  let real;
6
7
  try {
@@ -14,6 +15,7 @@ export function assertConfined(p, rootReal, label = "skill entry") {
14
15
  }
15
16
  }
16
17
  export function loadSkills(dir, opts) {
18
+ const logger = opts?.logger ?? createLogger("warn");
17
19
  let entries;
18
20
  try {
19
21
  entries = readdirSync(dir, { withFileTypes: true });
@@ -41,7 +43,10 @@ export function loadSkills(dir, opts) {
41
43
  if (confineRoot !== undefined)
42
44
  assertConfined(join(dir, entry.name), confineRoot);
43
45
  const raw = readFileSync(join(dir, entry.name), "utf8");
44
- push(parseSkill(raw, entry.name.replace(/\.md$/, "")), join(dir, entry.name));
46
+ const source = join(dir, entry.name);
47
+ const parsed = parseSkill(raw, entry.name.replace(/\.md$/, ""), source, logger);
48
+ if (parsed !== undefined)
49
+ push(parsed, source);
45
50
  }
46
51
  else if (isDirLike(entry, join(dir, entry.name))) {
47
52
  const skillDir = join(dir, entry.name);
@@ -56,7 +61,9 @@ export function loadSkills(dir, opts) {
56
61
  }
57
62
  if (confineRoot !== undefined)
58
63
  assertConfined(join(skillDir, "SKILL.md"), confineRoot);
59
- const skill = parseSkill(raw, entry.name);
64
+ const skill = parseSkill(raw, entry.name, join(skillDir, "SKILL.md"), logger);
65
+ if (skill === undefined)
66
+ continue;
60
67
  const files = collectAttachments(skillDir, "", confineRoot);
61
68
  if (files.length > 0)
62
69
  skill.spec.files = files;
@@ -67,8 +74,8 @@ export function loadSkills(dir, opts) {
67
74
  }
68
75
  return out;
69
76
  }
70
- export function loadDeploymentSkills(config) {
71
- return loadSkills(config.skillsDir, { toolsShareThisFilesystem: toolsRunOnThisHost(config) });
77
+ export function loadDeploymentSkills(config, logger) {
78
+ return loadSkills(config.skillsDir, { toolsShareThisFilesystem: toolsRunOnThisHost(config), ...(logger !== undefined ? { logger } : {}) });
72
79
  }
73
80
  function collectAttachments(skillDir, rel, confineRoot) {
74
81
  const files = [];
@@ -93,8 +100,19 @@ function collectAttachments(skillDir, rel, confineRoot) {
93
100
  }
94
101
  return files;
95
102
  }
96
- function parseSkill(raw, fallbackName) {
97
- const { meta, body } = parseFrontmatter(raw);
103
+ function parseSkill(raw, fallbackName, source, logger) {
104
+ const fm = parseFrontmatter(raw);
105
+ if (fm.kind === "unclosed") {
106
+ logger.warn("skill_refused", {
107
+ skill: fallbackName,
108
+ source,
109
+ reason: "frontmatter_unclosed",
110
+ note: "the file opens a frontmatter fence (`---`) that is never closed, so its `scenarios` restriction cannot be read — this skill is NOT loaded (it is not demoted to a global skill); close the fence or remove the opening line",
111
+ });
112
+ return undefined;
113
+ }
114
+ const meta = fm.kind === "block" ? fm.meta : {};
115
+ const body = fm.body;
98
116
  const name = meta.name ?? fallbackName;
99
117
  const description = meta.description ?? firstHeading(body) ?? name;
100
118
  const scenarios = (meta.scenarios ?? "")
@@ -106,17 +124,19 @@ function parseSkill(raw, fallbackName) {
106
124
  export function skillsForScenario(loaded, scenario) {
107
125
  return loaded.filter((k) => k.scenarios.length === 0 || k.scenarios.includes(scenario)).map((k) => k.spec);
108
126
  }
127
+ const FRONTMATTER_OPENS_RE = /^---[ \t]*\r?(?:\n|$)/;
128
+ const FRONTMATTER_BLOCK_RE = /^---[ \t]*\r?\n(?:---[ \t]*\r?(?:\n|$)|([\s\S]*?)\r?\n---[ \t]*\r?(?:\n|$))([\s\S]*)$/;
109
129
  export function parseFrontmatter(raw) {
110
- const m = /^---\r?\n([\s\S]*?)\r?\n---[ \t]*\r?(?:\n|$)([\s\S]*)$/.exec(raw);
130
+ const m = FRONTMATTER_BLOCK_RE.exec(raw);
111
131
  if (!m)
112
- return { meta: {}, body: raw };
132
+ return FRONTMATTER_OPENS_RE.test(raw) ? { kind: "unclosed" } : { kind: "absent", body: raw };
113
133
  const meta = {};
114
- for (const line of m[1].split("\n")) {
134
+ for (const line of (m[1] ?? "").split("\n")) {
115
135
  const kv = /^([A-Za-z0-9_-]+):\s*(.*)$/.exec(line.trim());
116
136
  if (kv)
117
137
  meta[kv[1]] = kv[2].trim();
118
138
  }
119
- return { meta, body: m[2] };
139
+ return { kind: "block", meta, body: m[2] };
120
140
  }
121
141
  function firstHeading(body) {
122
142
  for (const line of body.split("\n")) {
@@ -1,4 +1,5 @@
1
- export const LONGTAIL_DEFER_TOOLS = new Set(["SelectEnvironment"]);
1
+ import { SELECT_ENVIRONMENT_TOOL_NAME } from "./host-tool-names.js";
2
+ export const LONGTAIL_DEFER_TOOLS = new Set([SELECT_ENVIRONMENT_TOOL_NAME]);
2
3
  export function applyLongtailDefer(tools, enabled) {
3
4
  if (!enabled)
4
5
  return tools;
@@ -16,7 +16,7 @@ import { MODEL_PROVIDER_WORDS } from "./model-provider.js";
16
16
  import { buildDisplaySafeUrl } from "./trace/redact.js";
17
17
  import { describeAllowlistPostures } from "./env-name-allowlist-knobs.js";
18
18
  import { buildOutboundProxyPosture } from "./outbound-dispatcher.js";
19
- import { modelSupportsImages } from "./model-select.js";
19
+ import { modelImageInput, modelReasoningDecl } from "./model-select.js";
20
20
  export const CATALOG_VALUE_TYPES = ["boolean", "number", "string", "enum", "csv", "json", "path", "url", "secret", "opaque"];
21
21
  export const CATALOG_TIMINGS = ["hot", "restart", "deploy", "inert"];
22
22
  export const CATALOG_DANGER_AXES = ["security", "billing", "data"];
@@ -164,7 +164,7 @@ export const CONFIG_CATALOG = [
164
164
  r("GIT_API_BASEURL", "integrations", "url", "repo 工具的 Git host API base", { configKey: "gitApiBaseUrl" }),
165
165
  r("GIT_API_KIND", "integrations", "enum", "Git host API 方言", { enumValues: ["gitea", "github"], staticDefault: "gitea", configKey: "gitApiKind" }),
166
166
  r("GIT_API_TOKEN", "integrations", "secret", "repo 工具的 Git host 凭据", { danger: SEC }),
167
- r("HOOKS_TIMEOUT_MS", "orchestration", "number", "每只 hook 席位单次调用时限(ms;0=立即到期是合法值)", { derivedDefaultNote: "缺席 ⇒ 不铸键,core 自默认 600s" }),
167
+ r("HOOKS_TIMEOUT_MS", "orchestration", "number", "请求 settings.hooks 注册每个 handler 的时间预算(ms;0=零预算是合法值)", { derivedDefaultNote: "缺席 ⇒ 不铸键,读法 settingsHooksBudgetMs 取 600000" }),
168
168
  r("HOST_BG_DEFAULT_TIMEOUT_SEC", "orchestration", "number", "host 后台 shell 缺省超时(秒)", { staticDefault: "300" }),
169
169
  r("HOST_BG_ENABLED", "orchestration", "boolean", "host 车道后台 shell 开关", { staticDefault: "true" }),
170
170
  r("HOST_BG_FILE_CAP", "orchestration", "number", "host 后台 shell 磁盘护栏(字节;失控输出被 reap)", { staticDefault: String(64 * 1024 * 1024) }),
@@ -225,7 +225,7 @@ export const CONFIG_CATALOG = [
225
225
  r("LOCKED_CONFIG_KEYS", "auth", "csv", "管理员锁定层声明(词表=core 闭集注册表,未知键拒启)", { danger: SEC, configKey: "lockedConfigKeys" }),
226
226
  r("LOG_LEVEL", "observability", "string", "日志档位", { staticDefault: "info", configKey: "logLevel" }),
227
227
  r("LSP_ENABLED", "orchestration", "boolean", "LSP 沙箱腿 opt-in —— 本版 e2b / k8s 执行环境不实现绑定读,开了也不挂(起服一行 lsp_not_mounted);host 腿另有 LSP_HOST_ENABLED", { staticDefault: "false", configKey: "lspEnabled" }),
228
- r("LSP_ENV_ALLOW", "orchestration", "secret", `host 腿语言服务器子进程 env 的点名放行名单(点到的键从服务 env 原样放回、部署方显式承担;没点到的照剥;与 host shell inheritEnv:[names] 同一只谓词;形错 / 点名任一只名单型旋钮(含自己)拒启且不回显值;本进程环境里没有的名按序号 warn、不放行、不回显;多租户姿态(忽略时起服 warn 一次):${describeAllowlistPostures()};原文按凭据类对待:只回在场位、不进任何子进程,生效名单见起服披露行 allowed)`, { danger: SEC, derivedDefaultNote: "缺席 / 空串 ⇒ 空名单 = 全剥(7.100.0 行为)" }),
228
+ r("LSP_ENV_ALLOW", "orchestration", "secret", `host 腿语言服务器子进程 env 的点名放行名单(点到的键从服务 env 原样放回、部署方显式承担;没点到的照剥;与 host shell inheritEnv:[names] 同一只谓词;形错 / 点名任一只名单型旋钮(含自己)/ 点名本服务自有凭据名(剥后放回会把引擎刚扣下的凭据交回去;判官 = 引擎拒白名单的同一只)拒启且不回显值;本进程环境里没有的名按序号 warn、不放行、不回显;多租户姿态(忽略时起服 warn 一次):${describeAllowlistPostures()};原文按凭据类对待:只回在场位、不进任何子进程,生效名单见起服披露行 allowed)`, { danger: SEC, derivedDefaultNote: "缺席 / 空串 ⇒ 空名单 = 全剥(7.100.0 行为)" }),
229
229
  r("LSP_HOST_ENABLED", "orchestration", "boolean", "LSP host 腿开关(本机 language server,优雅降级)", { staticDefault: "true", configKey: "lspHostEnabled" }),
230
230
  r("MANUAL_MODE_SHELL_GATE", "approval", "enum", "手动模式 shell 门收紧腿(off=no-op 非放松 —— 本键只有收紧半场;拼错拒启;S-877 起 classify 退役 = 拒启指路)", { danger: SEC, enumValues: ["always", "off"], echoWords: ["always"], resolve: (c) => c.manualModeShellGate ?? null, derivedDefaultNote: "off/未设 ⇒ 本键不贡献任何东西(归一成键缺席)⇒ 回显 null;真姿态只有 always 一个(core 7.34.0 起形状档在每一种模式下都装,classify 不再是运维选的档)" }),
231
231
  r("MAX_PRINCIPAL_COST_USD", "limitsHttp", "number", "per-principal 窗内成本天花板(0=关)", { staticDefault: "0", danger: BILL, configKey: "maxPrincipalCostUsd", center: cLimits("maxPrincipalCostUsd") }),
@@ -303,14 +303,18 @@ export const CONFIG_CATALOG = [
303
303
  r("MODEL_FIRST_BYTE_TIMEOUT_MS", "modelPlane", "number", `请求发出 → 响应头的等待(ms;缺席 = core 缺省 + 上传宽限;到点 core 自有一次加宽重试,配了 MODEL_GATEWAY_FALLBACK_URLS 也一样(之后才切备;server 不铸 firstByteRetries);0 = 该段不设引擎钟、传输层的响应头 / 响应体钟也关(TCP + TLS 建连仍归传输层自己的钟);自托管慢网关按排队 + prefill 留足;failover 拓扑想快切须显式设小;须为 [${FIRST_BYTE_TIMEOUT_BOUNDS.minMs}, ${FIRST_BYTE_TIMEOUT_BOUNDS.maxMs}] 内十进制整数,其余拒启)`, { derivedDefaultNote: "未设/空串 ⇒ 不铸键,跟随 core 缺省(本仓不复制上游数字;core 改缺省本旋钮照映不改)", resolve: (c) => c.resilience.firstByteTimeoutMs ?? null }),
304
304
  r("MODEL_FIRST_TOKEN_TIMEOUT_MS", "modelPlane", "number", "首 token 超时(ms;0 = 该段不设引擎钟、传输层的响应体钟也关 —— 开流不吐字的唯一看门狗;自托管长 prefill 后端按此档留足)", { staticDefault: String(RESILIENCE_DEFAULTS.firstTokenTimeoutMs.value) }),
305
305
  r("MODEL_FREQUENCY_PENALTY", "modelPlane", "number", "frequency_penalty 直通(压过 EXTRA_BODY 同键)"),
306
- r("MODEL_GATEWAY_BASEURL", "modelPlane", "url", "openai 兼容网关 base URL(S-623:**无出厂缺省** —— 配置能派发到的每条 openai 兼容路由都必须解析到显式端点(条目自己的 baseUrl,或本键),否则拒启 / 热路径整批拒,机读码 `config.model_route_endpoint_missing`,拒因点名条目并给出本机写法 `MODEL_GATEWAY_BASEURL=<本机网关>/v1`;anthropic 单路由部署不设本键合法;S-475:带 userinfo 拒启,机读码 `config.gateway_url_userinfo` —— WHATWG 禁止用带凭据的 URL 构造 fetch Request,凭据放 MODEL_API_KEY;S-483:解析不动/不透明形拒启,机读码 `config.model_route_url_invalid`;S-514:带 `#fragment` 拒启,机读码 `config.model_route_url_fragment`)", { derivedDefaultNote: "缺席 ⇒ 本部署没有网关(不铸键);有 openai 路由落不到端点 ⇒ 拒启", configKey: "gatewayBaseUrl", center: cModels("models[].baseUrl") }),
306
+ r("MODEL_GATEWAY_BASEURL", "modelPlane", "url", "openai 兼容网关 base URL(S-623:**无出厂缺省** —— 将要服务的那张表(目录被采纳判目录表,否则判 env 表)里每条 openai 兼容路由都必须解析到显式端点(条目自己的 baseUrl,或本键),否则拒启 / 热路径整批拒,机读码 `config.model_route_endpoint_missing`,拒因点名条目并给出本机写法 `MODEL_GATEWAY_BASEURL=<本机网关>/v1`;anthropic 单路由部署不设本键合法;S-475:带 userinfo 拒启,机读码 `config.gateway_url_userinfo` —— WHATWG 禁止用带凭据的 URL 构造 fetch Request,凭据放 MODEL_API_KEY;S-483:解析不动/不透明形拒启,机读码 `config.model_route_url_invalid`;S-514:带 `#fragment` 拒启,机读码 `config.model_route_url_fragment`)", { derivedDefaultNote: "缺席 ⇒ 本部署没有网关(不铸键);有 openai 路由落不到端点 ⇒ 拒启", configKey: "gatewayBaseUrl", center: cModels("models[].baseUrl") }),
307
307
  r("MODEL_GATEWAY_FALLBACK_URLS", "modelPlane", "url", "网关故障转移地址表(CSV;S-623:主网关 MODEL_GATEWAY_BASEURL 未设而本键设了 ⇒ 拒启,机读码 `config.gateway_fallback_without_primary` —— 备用是主网关的镜像;S-475:**逐项**判 userinfo,任一项带 ⇒ 拒启,机读码 `config.gateway_url_userinfo`;S-483:逐项判可解析性,机读码 `config.model_route_url_invalid`;S-514:**逐项**判 `#fragment`,机读码 `config.model_route_url_fragment`)", { configKey: "gatewayFallbackUrls" }),
308
- r("MODEL_ID", "modelPlane", "string", "主模型 id(3.0.0 起无出厂缺省,缺 ⇒ 拒启指路)", { configKey: "model", resolve: (c) => c.model.id, center: cModels("models[].id") }),
308
+ r("MODEL_ID", "modelPlane", "string", "主模型 id(3.0.0 起无出厂缺省;env 表的主槽。目录被采纳时整张换掉 env 表、本键不服务,目录第一次采纳那一拍说一行 `config_env_set_but_ineffective`;目录缺席时它是兜底,两者皆无 ⇒ 拒启指路)", { configKey: "model", resolve: (c) => c.model.id, center: cModels("models[].id") }),
309
309
  r("MODEL_IDLE_TIMEOUT_MS", "modelPlane", "number", "流中静默看门狗(ms;0 = 该段不设引擎钟、传输层的响应体钟也关)", { staticDefault: String(RESILIENCE_DEFAULTS.idleTimeoutMs.value) }),
310
310
  r("MODEL_MAX_TOKENS", "modelPlane", "number", "主模型输出上限", { derivedDefaultNote: "缺席 ⇒ min(32000, contextWindow)", resolve: (c) => c.model.maxTokens ?? null, center: cModels("models[].maxTokens") }),
311
311
  r("MODEL_PRESENCE_PENALTY", "modelPlane", "number", "presence_penalty 直通"),
312
312
  r("MODEL_PROVIDER", "modelPlane", "enum", "主模型 provider(路由选 brain;S-461 起是闭集,词表外的值启动期拒启并点名机读码 `config.model_provider_invalid`)", { enumValues: MODEL_PROVIDER_WORDS, derivedDefaultNote: "缺席:ANTHROPIC base+cred 同在 ⇒ anthropic,否则 gateway", resolve: (c) => c.model.provider, center: cModels("models[].provider") }),
313
- r("MODEL_REASONING", "modelPlane", "boolean", "主模型 reasoning 声明", { staticDefault: "true", resolve: (c) => c.model.reasoning ?? null, center: cModels("models[].reasoning") }),
313
+ r("MODEL_REASONING", "modelPlane", "boolean", "主模型 reasoning 声明(三态:true / false / 缺席 = 未声明)", {
314
+ derivedDefaultNote: "缺席 ⇒ 不铸 `Model.reasoning`(没有 true 缺省);引擎按真值读,缺席与 false 同读 —— 思考档不随请求发出;要开思考写 MODEL_REASONING=true。`GET /v1/models` 该行不带 `reasoning` 键",
315
+ resolve: (c) => modelReasoningDecl(c.model) ?? null,
316
+ center: cModels("models[].reasoning"),
317
+ }),
314
318
  r("MODEL_REASONING_EFFORT_LEVELS", "modelPlane", "csv", "openai 端点接受的思考档集(六档子集;高档 clamp-down 不 422;anthropic 腿不铸此键;未知词拒启)", {
315
319
  derivedDefaultNote: "缺席 ⇒ 不铸 compat,core 走保守梯(minimal|low|medium|high),xhigh/max 被 clamp 下来",
316
320
  resolve: (c) => {
@@ -332,7 +336,14 @@ export const CONFIG_CATALOG = [
332
336
  },
333
337
  }),
334
338
  r("MODEL_VERIFIER", "modelPlane", "string", "verify 门的异构 verifier(须命中目录;typo 回 default 并 boot warn=自评自批)", { derivedDefaultNote: "缺席/不在目录 ⇒ default(=implementer,去相关性失效警告)" }),
335
- r("MODEL_VISION", "modelPlane", "boolean", "主模型 vision 声明(false = 明说不收图:带图请求的图被换成占位句交给模型,提交时计数并告警)", { staticDefault: "true", resolve: (c) => modelSupportsImages(c.model), center: cModels("models[].vision") }),
339
+ r("MODEL_VISION", "modelPlane", "boolean", "主模型 vision 声明(三态:true / false / 缺席 = 未声明;false = 明说不收图:带图请求的图被换成占位句交给模型,提交时计数并告警)", {
340
+ derivedDefaultNote: "缺席 ⇒ 不铸 `Model.input`(没有 true 缺省);引擎与带图预检都按「收」读(图原样交给模型,不出信号);`GET /v1/models` 该行不带 `vision` 键。要让预检对纯文本模型出信号写 MODEL_VISION=false",
341
+ resolve: (c) => {
342
+ const v = modelImageInput(c.model);
343
+ return v === "undeclared" ? null : v === "yes";
344
+ },
345
+ center: cModels("models[].vision"),
346
+ }),
336
347
  r("MYSQL_DATABASE", "store", "string", "MySQL 协议库名(选中该引擎时必填)", { danger: DATA }),
337
348
  r("MYSQL_HOST", "store", "string", "MySQL 协议主机(在场即算 SQL 信号,参与 DB_BACKEND 默认推导)", { danger: DATA }),
338
349
  r("MYSQL_PASSWORD", "store", "secret", "MySQL 协议口令", { danger: SEC }),
@@ -373,7 +384,7 @@ export const CONFIG_CATALOG = [
373
384
  r("REAP_INTERVAL_SEC", "limitsHttp", "number", "reaper 周期(秒)", { staticDefault: "60", configKey: "reapIntervalSec" }),
374
385
  r("REAP_RUN_STALE_SEC", "limitsHttp", "number", "run 活性判陈旧阈(秒)", { staticDefault: "120", configKey: "runStaleSec", center: cLimits("runStaleSec") }),
375
386
  r("REMOTE_EXEC", "orchestration", "enum", "执行车道选择(点名而配不齐/认不出 ⇒ 拒启,绝不静默降级到 host/stub)", { enumValues: REMOTE_EXEC_PROVIDER_WORDS, danger: SEC, derivedDefaultNote: "缺席:CONFIG_PROVIDER=local ⇒ host;其余 ⇒ 进程内 stub(手带整族不挂;残余名册看活体 wiring_manifest 里 mountedBy=hands 的条目数,不按工具名点。想让这一形拒启见 REQUIRE_EXECUTION_LANE)", configKey: "remoteExec", resolve: (c) => c.remoteExec?.provider ?? null }),
376
- r("REMOTE_EXEC_HOME_DIR", "orchestration", "path", "执行环境的 home 目录(`~/` 形权限规则的基;core ExecutionEnv.homeDir 座)", { danger: SEC, derivedDefaultNote: "缺席:host/in-process ⇒ os.homedir();e2b ⇒ /home/user;k8s/local-docker/ssh/adb/device ⇒ 无(`~/` 规则 422 响亮拒)", configKey: "remoteExecHomeDir", resolve: (c) => c.remoteExecHomeDir ?? null }),
387
+ r("REMOTE_EXEC_HOME_DIR", "orchestration", "path", "执行环境的 home 目录(`~/` 形权限规则的基、引擎家锚拒读行的落点;core ExecutionEnv.homeDir 座)。local-docker / ssh 车道在每只执行环境开起来时与它的 $HOME 对证,不一致或问不出 ⇒ 那只环境不开", { danger: SEC, derivedDefaultNote: "缺席:host/in-process ⇒ os.homedir();e2b ⇒ /home/user;k8s/local-docker/ssh/adb/device ⇒ 无(`~/` 规则 422 响亮拒;泄内容的递归读全 shell 面真人问、只读面拒;起服 warn execution_lane_home_undeclared)", configKey: "remoteExecHomeDir", resolve: (c) => c.remoteExecHomeDir ?? null }),
377
388
  r("REQUIRE_EXECUTION_LANE", "orchestration", "boolean", "开了之后:REMOTE_EXEC 未点名 ∧ CONFIG_PROVIDER≠local ⇒ **拒启**并点名该设什么。默认关 = 照旧启动,但执行环境是进程内 stub、**零手带工具**(手带整族不挂;活体读数:mountedBy=hands 条目 10 → 0),名册里其余工具照常执行,任务仍回 status=completed —— 凡需要手的请求,与「模型不肯用工具」在用户面同形。判据 = 活体 wiring_manifest 里 mountedBy=hands 的条目数,不按工具名点;名册总条数随 core 版本走,不写死。托管/云部署推荐开(docs/DEPLOY-PREREQS.md)", { staticDefault: "false", danger: SEC, configKey: "requireExecutionLane" }),
378
389
  r("REQUIRE_PRINCIPAL", "auth", "boolean", "多租户开关(posture 判别位:true ⇒ CC 能力族默认收紧)", { staticDefault: "false", danger: SEC, configKey: "requirePrincipal" }),
379
390
  r("RESOURCE_SUSPEND", "approval", "boolean", "durable 路径 opt-in core resourceSuspend(预算/preempt ⇒ 可恢复挂起)", { staticDefault: "false", configKey: "resourceSuspend" }),
@@ -438,7 +449,7 @@ export const CONFIG_CATALOG = [
438
449
  r("SIGHUP_IDLE_GRACE_MS", "limitsHttp", "number", "SIGHUP 空闲关停窗(ms;共享引擎形防误杀)", { staticDefault: "120000", configKey: "sighupIdleGraceMs" }),
439
450
  r("SKILLS_DIR", "integrations", "path", "出厂 skill 目录(设了就整个替换包内 skills/,不叠加;配置源的技能再按名盖上)", { derivedDefaultNote: "缺席 ⇒ 包内 skills/(相对模块解析,不是 cwd)", configKey: "skillsDir" }),
440
451
  r("SNAPSHOT_BLOB_ALLOW_SQL_BYTES", "store", "boolean", "云形缺 MinIO 时显式接受 SQL 店放快照字节(严格 'true';安全姿势开关不收宽松真值)", { staticDefault: "false", danger: DATA, configKey: "snapshotBlobAllowSql" }),
441
- r("SNAPSHOT_BLOB_SQL_MAX_BYTES", "store", "number", "SQL 店单 blob 帽(字节)", { derivedDefaultNote: "缺席:mysql 引擎 ⇒ 内建默认帽;pg ⇒ 不设", configKey: "snapshotBlobSqlMaxBytes" }),
452
+ r("SNAPSHOT_BLOB_SQL_MAX_BYTES", "store", "number", "SQL 店单 blob 帽(字节)", { derivedDefaultNote: "缺席:mysql 引擎 ⇒ 库报的单行上限与 max_allowed_packet ÷ 2 取小(两堵墙各自读不到时按该库族文档缺省);pg ⇒ 不设", configKey: "snapshotBlobSqlMaxBytes" }),
442
453
  r("SSH_HOST", "orchestration", "string", "ssh 车道目标主机(必需件)"),
443
454
  r("SSH_HOST_FINGERPRINT", "orchestration", "string", "主机密钥指纹校验(坏值拒启;仅 ssh 车道被选中时求值)", { danger: SEC }),
444
455
  r("SSH_KNOWN_HOSTS", "orchestration", "path", "known_hosts 路径(坏路径拒启)", { danger: SEC }),
@@ -488,12 +499,12 @@ export const CONFIG_CATALOG = [
488
499
  r("WORKFLOW_SIZE_GUIDELINE", "orchestration", "enum", "Workflow 工具卡的规模建议(advisory;typo 拒启)", { enumValues: ["small", "medium", "large", "unrestricted"], configKey: "workflowSizeGuideline" }),
489
500
  r("WORKFLOW_TOTAL_TIMEOUT_MS", "orchestration", "number", "workflow 脚本总时限(ms;0/负不是禁用 —— 无禁用臂)", { staticDefault: "3600000" }),
490
501
  r("WORKSPACE_CACHE", "orchestration", "enum", "k8s 按工作区空间的构建缓存卷:volume = 每个空间(会话住客)一只 PVC(ws-cache-<摘要>,标签 sema.space,StorageClass 用集群缺省),挂到 WORKSPACE_CACHE_MOUNT,并在 pod env 注入工具缓存闭表(GRADLE_USER_HOME / MAVEN_OPTS / npm_config_cache / PIP_CACHE_DIR / UV_CACHE_DIR / GOMODCACHE;Rust 依赖缓存不盖 —— Cargo 没有只放下载缓存的 env;K8S_SANDBOX_ENV 同名显式值胜);卷在快照之外、可丢,pod 删卷留;卷拿不到(建不成 / 快照时限内没绑定)⇒ run 照起、无卷无缓存 env,fail-open 计数 + 一行 workspace_cache_unavailable;off = 不建卷。前提:会话店读得出会话住客(内存会话店 × volume ⇒ 拒启);委派子代不挂卷;词表外拒启", { enumValues: WORKSPACE_CACHE_WORDS, staticDefault: WORKSPACE_CACHE_DEFAULT }),
491
- r("WORKSPACE_CACHE_MOUNT", "orchestration", "path", "k8s 构建缓存卷在沙箱 pod 里的挂载点(绝对路径;与工作区挂载 K8S_MOUNT_PATH 相同 / 互相嵌套 ⇒ 拒启;只在 WORKSPACE_CACHE=volume 时读)", { staticDefault: WORKSPACE_CACHE_MOUNT_DEFAULT }),
502
+ r("WORKSPACE_CACHE_MOUNT", "orchestration", "path", "k8s 构建缓存卷在沙箱 pod 里的挂载点(绝对路径;与工作区挂载 K8S_MOUNT_PATH 相同 / 互相嵌套 ⇒ 拒启;落在保留的镜像目录闭集上 / 之下 / 之上 ⇒ 拒启并点名那一项 —— /bin /boot /dev /etc /home/sandbox /lib /lib64 /opt/sema /proc /root /run /sbin /sys /tmp /usr /var;只在 WORKSPACE_CACHE=volume 时读)", { staticDefault: WORKSPACE_CACHE_MOUNT_DEFAULT }),
492
503
  r("WORKSPACE_CACHE_SIZE", "orchestration", "string", "k8s 构建缓存卷的大小(PVC 申请量,k8s quantity 形如 20Gi / 500Mi;形不合拒启;只在 WORKSPACE_CACHE=volume 时读)", { staticDefault: WORKSPACE_CACHE_SIZE_DEFAULT }),
493
504
  r("WORKSPACE_FILE_MAX_BYTES", "limitsHttp", "number", "已随 workspace 浏览面退役(S-15):值照常校验/落值,应用于空(重启也不生效)", { envTiming: "inert", configKey: "workspaceFileMaxBytes", center: cLimits("workspaceFileMaxBytes", { timing: "inert" }) }),
494
505
  r("WORKSPACE_PERSIST", "orchestration", "enum", "k8s 工作区跨轮保留:space(缺省)= 每条 run 结束把 /workspace 快照进本会话住客的空间、下一条 run 开始恢复最近一份(上一条还在保存 ⇒ 下一条等它存完,最多等一个上传时限,见 USAGE §9.3b);off = 每轮新建。space(含缺省)却没配快照存储(MINIO_* 三键)⇒ 不生效,起服一行 workspace_persist_unavailable 点名缺键;前提:会话店读得出会话住客(local / SQL 会话店),内存会话店 × space(含缺省,且配了快照存储)⇒ 拒启(出路 WORKSPACE_PERSIST=off);词表外拒启", { enumValues: WORKSPACE_PERSIST_WORDS, staticDefault: WORKSPACE_PERSIST_DEFAULT, danger: DATA }),
495
506
  r("WORKSPACE_SNAPSHOT_BUCKET", "orchestration", "string", "k8s 工作区快照桶", { derivedDefaultNote: "缺席 ⇒ workspaces" }),
496
- r("WORKSPACE_SNAPSHOT_EXCLUDE", "orchestration", "csv", "k8s 工作区快照的排除表(相对工作区根的 tar 排除模式,逗号分隔,如 build,.gradle,node_modules/.cache;每项一个 --exclude=./<项>,run 末快照与停驻挂起同一张表 —— 排除的目录恢复后不在,构建产物本就可再生;项形闭:相对路径段,不含 .. / 前导 / / 空白 / 引号,坏项拒启并点名第几项;不读项目 .gitignore)", { derivedDefaultNote: "缺席 = 不排除(上传命令与旧版逐字同)" }),
507
+ r("WORKSPACE_SNAPSHOT_EXCLUDE", "orchestration", "csv", "k8s 工作区快照的排除表(相对工作区根的 tar 排除模式,逗号分隔,如 build,.gradle,node_modules/.cache;每项一个 --exclude=./<项>,run 末快照与停驻挂起同一张表 —— 排除的目录恢复后不在,构建产物本就可再生;项形闭:相对路径段,不含 .. / 前导 / / 空白 / 引号,整体通配(只由 * / ? 组成的项,* 会让快照一个顶层项都不剩)也拒,坏项拒启并点名第几项;不读项目 .gitignore)", { derivedDefaultNote: "缺席 = 不排除(上传命令与旧版逐字同)" }),
497
508
  r("WORKSPACE_SNAPSHOT_KEEP", "orchestration", "number", `k8s 工作区每个空间(会话住客)保留的快照份数(整数 [${WORKSPACE_SNAPSHOT_KEEP_RANGE.min}, ${WORKSPACE_SNAPSHOT_KEEP_RANGE.max}];写新快照后删最老的;域外拒启)`, { staticDefault: String(WORKSPACE_SNAPSHOT_KEEP_DEFAULT), danger: DATA }),
498
509
  r("WORKSPACE_SNAPSHOT_PREFIX", "orchestration", "string", "k8s 工作区快照 key 前缀"),
499
510
  r("WORKSPACE_SNAPSHOT_TIMEOUT_MS", "orchestration", "number", `k8s 工作区快照的时限(毫秒,整数 [${WORKSPACE_SNAPSHOT_TIMEOUT_MS_RANGE.min}, ${WORKSPACE_SNAPSHOT_TIMEOUT_MS_RANGE.max}];域外拒启):一个数管四处 —— run 末上传与连沙箱时恢复的墙钟上界、空间结束时回收座一次调用的绝对截止(卷与对象都在内)、下一条 run 等上一条存完的最长等待(提交围栏的存活上界);大文件读写的墙钟也是它。大工作区(构建目录 GB 级)撞上界 ⇒ 调大它或配 WORKSPACE_SNAPSHOT_EXCLUDE`, { staticDefault: String(WORKSPACE_SNAPSHOT_TIMEOUT_MS_DEFAULT) }),
@@ -232,8 +232,8 @@ export const CONFIG_CROSS_INVARIANTS = [
232
232
  id: "model-route-endpoint",
233
233
  keys: ["gatewayBaseUrl", "gatewayFallbackUrls", "anthropic", "models"],
234
234
  restartReason: "model-route-endpoint",
235
- bootAnchor: { file: "src/config.ts", marker: "CROSS-INVARIANT:model-route-endpoint" },
236
- check: ({ live, next }) => (next.models === live.models ? undefined : modelRouteEndpointRefusal(next)),
235
+ bootAnchor: { file: "src/boot/stage-02-web-admin-pull.ts", marker: "CROSS-INVARIANT:model-route-endpoint" },
236
+ check: ({ live, next }) => (next.models === live.models ? undefined : modelRouteEndpointRefusal(next, "catalog")),
237
237
  },
238
238
  {
239
239
  id: "default-model-resolvable",
@@ -1,8 +1,8 @@
1
1
  import { type MigrationReceipt } from "@sema-agent/settings-schema/one-time-migrations";
2
- import type { PromptsDomainFaces } from "./prompts-domain-validate.js";
3
- /** 落盘信封。`effective`/`etag` 逐字=当时的 fetchEffective 返回(JSON verbatim 面)。`formatVersion` 的语义见头注(4 = 载荷是 settings-schema 11 的形)。 */
2
+ import type { PublishedPromptArtifact } from "@sema-agent/core";
3
+ /** 落盘信封。`effective`/`etag` 逐字=当时的 fetchEffective 返回(JSON verbatim 面)。`formatVersion` 的语义见头注(5 = 载荷的 prompts 是中心层唯一的那种 wire 形)。 */
4
4
  export interface PersistedLkg {
5
- formatVersion: 4;
5
+ formatVersion: 5;
6
6
  savedAt: string;
7
7
  worker: string;
8
8
  /** 拉到这份候选时所用凭证的身份(`center-credential.ts`;摘要形,不含凭证原文)。 */
@@ -48,10 +48,10 @@ export declare function lkgReadDenyRows(configLkgPath: string | undefined): {
48
48
  /** 原子落盘一个干净候选(tmp+rename,0600)。BEST-EFFORT:失败=一条 warn 的素材(调用方发),绝不
49
49
  * 影响在飞的应用链——LKG 缓存丢失的代价只是下次冷启动回到 env 兜底。 */
50
50
  export declare function saveLkg(path: string, worker: string | undefined, identity: string, effective: Record<string, unknown>, etag: string | undefined): Promise<void>;
51
- /** 一次读回做过的一次性迁移(调用方响亮打一行 `config_lkg_migrated`,并按 4 写回原位):`fromFormat` = 盘上的版本号;`note` = 信封层的说明
52
- * (2 → 3 那一步,{@link migrateV2Lkg});`receipts` = 载荷层 settings-schema 迁移的收据(只点名坐标与处置,不带值)。 */
51
+ /** 一次读回做过的一次性迁移(调用方响亮打一行 `config_lkg_migrated`,并按 5 写回原位):`fromFormat` = 盘上的版本号;`note` = 信封层的说明
52
+ * (2 → 3 那一步 {@link migrateV2Lkg} / 4 → 5 那一步 {@link migrateV4Lkg});`receipts` = 载荷层 settings-schema 迁移的收据(只点名坐标与处置,不带值)。 */
53
53
  export interface LkgReadMigration {
54
- readonly fromFormat: 2 | 3 | 4;
54
+ readonly fromFormat: 2 | 3 | 4 | 5;
55
55
  readonly note?: string;
56
56
  readonly receipts: readonly MigrationReceipt[];
57
57
  }
@@ -59,12 +59,12 @@ export interface LkgReadMigration {
59
59
  * 读盘上 LKG。返回 undefined 的所有情形都「安静地回 env 兜底」(调用方 warn 点名 reason):
60
60
  * 文件缺席/JSON 坏/信封形不对/worker 或凭证身份不匹配(防同名文件跨 worker / 跨账号串包;`CONFIG_LKG_PATH`
61
61
  * 单一路径时这是唯一的一道)/载荷有迁不动的旧形({@link migrateLkgPayload})/prompts 面复判失败。
62
- * `migrated`:读回时做过一次性迁移(信封 2 → 3 或载荷的 settings-schema 迁移)—— 调用方响亮打一行,并把交回的 4 写回原位。
63
- * `prompts`:候选判官对这份载荷 prompts 面交出的已判形值(`undefined` = 载荷不带 prompts 键)—— 调用方采纳 prompts 直接用它。
62
+ * `migrated`:读回时做过一次性迁移(信封 2 → 3 / 4 → 5 或载荷的 settings-schema 迁移)—— 调用方响亮打一行,并把交回的 5 写回原位。
63
+ * `prompts`:候选判官对这份载荷 prompts 面交出的中心层(引擎 verify 过的发布形 artifact;`undefined` = 载荷不带 prompts 键)—— 调用方采纳直接用它。
64
64
  */
65
65
  export declare function loadLkg(path: string, worker: string | undefined, identity: string): Promise<{
66
66
  lkg: PersistedLkg;
67
- prompts: PromptsDomainFaces | undefined;
67
+ prompts: PublishedPromptArtifact | undefined;
68
68
  migrated?: LkgReadMigration;
69
69
  } | {
70
70
  lkg?: undefined;
@@ -27,7 +27,7 @@ export function lkgReadDenyRows(configLkgPath) {
27
27
  return [{ pattern: configLkgPath, caseSensitive: false }];
28
28
  }
29
29
  export async function saveLkg(path, worker, identity, effective, etag) {
30
- const body = { formatVersion: 4, savedAt: new Date().toISOString(), worker: worker ?? "global", identity, ...(etag !== undefined ? { etag } : {}), effective };
30
+ const body = { formatVersion: 5, savedAt: new Date().toISOString(), worker: worker ?? "global", identity, ...(etag !== undefined ? { etag } : {}), effective };
31
31
  const tmp = `${path}.${randomBytes(6).toString("hex")}.tmp`;
32
32
  await fs.mkdir(dirname(path), { recursive: true });
33
33
  await fs.writeFile(tmp, JSON.stringify(body), { mode: 0o600 });
@@ -54,7 +54,7 @@ export async function loadLkg(path, worker, identity) {
54
54
  const formatVersion = p.formatVersion;
55
55
  if (formatVersion === 1)
56
56
  return { reason: "pre-identity LKG (formatVersion 1) — not read back: it cannot prove whose credential fetched it (S-651); the next clean candidate rewrites it" };
57
- if (formatVersion !== 2 && formatVersion !== 3 && formatVersion !== 4)
57
+ if (formatVersion !== 2 && formatVersion !== 3 && formatVersion !== 4 && formatVersion !== 5)
58
58
  return { reason: `unknown formatVersion ${String(formatVersion)}` };
59
59
  if (typeof p.worker !== "string" || p.worker !== (worker ?? "global"))
60
60
  return { reason: `worker mismatch (file=${String(p.worker)})` };
@@ -71,14 +71,20 @@ export async function loadLkg(path, worker, identity) {
71
71
  envelope = v2.lkg;
72
72
  note = v2.migrated;
73
73
  }
74
+ if (formatVersion !== 5) {
75
+ const v4 = migrateV4Lkg(envelope, formatVersion);
76
+ if (v4.lkg === undefined)
77
+ return v4;
78
+ note = note === undefined ? v4.migrated : `${note}; ${v4.migrated}`;
79
+ }
74
80
  const payload = migrateLkgPayload(envelope.effective);
75
81
  if ("refused" in payload)
76
82
  return { reason: payload.refused };
77
83
  const judged = lkgPayloadJudged(payload.effective, envelope.etag);
78
84
  if ("problem" in judged)
79
85
  return { reason: judged.problem };
80
- const lkg = { ...envelope, formatVersion: 4, effective: payload.effective };
81
- const migrated = formatVersion !== 4 || payload.receipts.length > 0;
86
+ const lkg = { ...envelope, formatVersion: 5, effective: payload.effective };
87
+ const migrated = formatVersion !== 5 || payload.receipts.length > 0;
82
88
  return migrated ? { lkg, prompts: judged.prompts, migrated: { fromFormat: formatVersion, ...(note !== undefined ? { note } : {}), receipts: payload.receipts } } : { lkg, prompts: judged.prompts };
83
89
  }
84
90
  export function migrateLkgPayload(effective) {
@@ -93,6 +99,16 @@ export function migrateLkgPayload(effective) {
93
99
  }
94
100
  return { effective: m.effective, receipts: m.receipts };
95
101
  }
102
+ function migrateV4Lkg(lkg, fromFormat) {
103
+ if (Object.hasOwn(lkg.effective, "prompts")) {
104
+ return {
105
+ reason: `formatVersion ${fromFormat} LKG carries a prompts face` +
106
+ " — written before 7.132.0, so it is the retired two-axis wire (declarations / v1 catalog) the engine no longer reads; not read back: " +
107
+ "the center's next candidate (republished as {schemaVersion: 2, artifact}) rewrites it",
108
+ };
109
+ }
110
+ return { lkg, migrated: `formatVersion ${fromFormat} → 5 (one-time): the payload carries no prompts face, read back unchanged` };
111
+ }
96
112
  const RETIRED_CATALOG_COORDINATE = /^models\.(0|[1-9][0-9]*)$/;
97
113
  function migrateDroppedIdentityRow(row) {
98
114
  if (row === null || typeof row !== "object")
@@ -1,4 +1,4 @@
1
- import { type DroppedConfigEntry, type RetiredDomainFinding, type UnreadConfigFile } from "./web-admin-client/read-warnings.js";
1
+ import { type DroppedConfigEntry, type RetiredDomainFinding, type UnreadConfigFile, type UnreadConfigKey } from "./web-admin-client/read-warnings.js";
2
2
  import { FileConfigStore } from "@sema-agent/settings-schema/node";
3
3
  import { type EffectiveConfig as AgentConfigEffective, type EffectiveReadWarning } from "@sema-agent/settings-schema";
4
4
  import { fetchEffective as remoteFetchEffective, fetchSkillContent as remoteFetchSkillContent, type EffectiveConfig } from "./web-admin-client/facade.js";
@@ -28,6 +28,7 @@ import type { ConfigProviderWord } from "./config-types.js";
28
28
  /** `retiredDomains`(S-1456):带事实的退役域文档(契约包的墓碑)—— 读腿不抛,交成发现,候选判官以成因 `retired_domain` 整拒这份候选(与域判形失败
29
29
  * 同一条回落链、同一行拒判);缺席 = 没有。远端腿:那一键不进 effective、其余域照读;本地腿:契约读腿在读便携域之前就拒,交出的候选只有版本
30
30
  * (这棵树的内容版本,哈希含退役文件 ⇒ 改 / 删它版本即变),内容是空的 effective(被整拒,不会被应用)。 */
31
+ /** `unreadKeys`:本地读腿读了那份文件、却结构上不读其中一键(`prompts.json` 的 `workers`)—— 同 `unreadFiles`,不进候选门,调用方一键一行 `config_unread_key`。 */
31
32
  export type FetchEffectiveResult = {
32
33
  effective: EffectiveConfig;
33
34
  etag?: string;
@@ -37,6 +38,7 @@ export type FetchEffectiveResult = {
37
38
  }>;
38
39
  droppedEntries?: DroppedConfigEntry[];
39
40
  unreadFiles?: UnreadConfigFile[];
41
+ unreadKeys?: UnreadConfigKey[];
40
42
  retiredDomains?: RetiredDomainFinding[];
41
43
  readWarnings: readonly EffectiveReadWarning[];
42
44
  credentialIdentity?: string;
@@ -2,7 +2,7 @@ import { readMcpSourceLabel } from "./mcp-source-label.js";
2
2
  import { createHmac, randomBytes } from "node:crypto";
3
3
  import { retiredDomainFindingOf, splitFoldedReadWarnings, withDroppedCatalogEntries } from "./web-admin-client/read-warnings.js";
4
4
  import { FileConfigStore } from "@sema-agent/settings-schema/node";
5
- import { danglingRefs, emptyEffective, findSkillContent, renderRefIssue, skillContentHash, } from "@sema-agent/settings-schema";
5
+ import { danglingRefs, emptyEffective, findSkillContent, promptArtifactFor, renderRefIssue, skillContentHash, } from "@sema-agent/settings-schema";
6
6
  import { redactSecrets } from "./trace/redact.js";
7
7
  import { fetchEffective as remoteFetchEffective, fetchSkillContent as remoteFetchSkillContent, WebAdminHttpError, } from "./web-admin-client/facade.js";
8
8
  import { homedir } from "node:os";
@@ -120,6 +120,7 @@ export class LocalConfigProvider {
120
120
  const droppedEntries = folded.droppedEntries.map(redactDroppedEntry);
121
121
  const errors = [...domainErrors.map((de) => ({ domain: de.domain, error: redactConfigError(de.error) })), ...parseErrors, ...refErrors];
122
122
  this.#servedSkills = eff.skills;
123
+ const unreadKeys = localUnreadPromptKeys(eff.prompts);
123
124
  return {
124
125
  effective: withDroppedCatalogEntries(mapToServiceEffective(eff, eff.version), folded.droppedCatalogEntries),
125
126
  etag: tag,
@@ -127,6 +128,7 @@ export class LocalConfigProvider {
127
128
  ...(errors.length > 0 ? { domainErrors: errors } : {}),
128
129
  ...(droppedEntries.length > 0 ? { droppedEntries } : {}),
129
130
  ...(folded.unreadFiles.length > 0 ? { unreadFiles: folded.unreadFiles } : {}),
131
+ ...(unreadKeys.length > 0 ? { unreadKeys } : {}),
130
132
  ...(retired !== undefined ? { retiredDomains: [retired] } : {}),
131
133
  };
132
134
  }
@@ -134,6 +136,14 @@ export class LocalConfigProvider {
134
136
  return findSkillContent(this.#servedSkills, contentHash);
135
137
  }
136
138
  }
139
+ function localUnreadPromptKeys(prompts) {
140
+ const names = prompts?.workers === undefined ? [] : Object.keys(prompts.workers);
141
+ return names.length === 0 ? [] : [{ file: "prompts.json", domain: "prompts", key: "workers", names }];
142
+ }
143
+ function localPromptsWire(prompts, version) {
144
+ const artifact = prompts === undefined ? undefined : promptArtifactFor(prompts, null);
145
+ return artifact === undefined ? {} : { prompts: { schemaVersion: 2, artifact: { ...artifact, sourceRevision: `local:r${version}` } } };
146
+ }
137
147
  export function mapToServiceEffective(eff, version) {
138
148
  return {
139
149
  version,
@@ -149,8 +159,8 @@ export function mapToServiceEffective(eff, version) {
149
159
  ...(m.sealedApiKey !== undefined ? { sealedApiKey: m.sealedApiKey } : {}),
150
160
  ...(m.quotaWeight !== undefined ? { quotaWeight: m.quotaWeight } : {}),
151
161
  tier: m.tier,
152
- reasoning: m.reasoning,
153
- vision: m.vision,
162
+ ...(m.reasoning !== undefined ? { reasoning: m.reasoning } : {}),
163
+ ...(m.vision !== undefined ? { vision: m.vision } : {}),
154
164
  ...(m.contextWindow !== undefined ? { contextWindow: m.contextWindow } : {}),
155
165
  ...(m.maxTokens !== undefined ? { maxTokens: m.maxTokens } : {}),
156
166
  ...(typeof m.autoCompactTokens === "number" ? { autoCompactTokens: m.autoCompactTokens } : {}),
@@ -216,9 +226,7 @@ export function mapToServiceEffective(eff, version) {
216
226
  };
217
227
  }),
218
228
  },
219
- ...(eff.prompts?.catalog !== undefined
220
- ? { prompts: { schemaVersion: 1, catalog: eff.prompts.catalog } }
221
- : {}),
229
+ ...localPromptsWire(eff.prompts, version),
222
230
  scenarios: {
223
231
  scenarios: (eff.scenarios.scenarios ?? []).map((sc) => ({
224
232
  name: sc.name,
@@ -548,6 +548,12 @@ export interface ServiceConfigFlat {
548
548
  *
549
549
  * 🔴 **必填、无可选形**:一个 `?` 会立刻招来一条「缺席就回落 `config.model`」的臂,而那条臂正是本键
550
550
  * 要消灭的东西([ref]:同一语义面禁两个写者)。测试夹具与 `loadConfig` 一样,与 `model` 同源铸。
551
+ *
552
+ * 🔴 **同引用是契约**:env 表服务时 `model` 与 `envModel` **恒是同一个对象**(`loadConfig` 把同一只模型放进两个键)。
553
+ * `servedModelTableLeg`(`model-select.ts`)拿这条**引用相等**当「这个进程服务的是哪张表」的唯一状态位 —— `model` 换成目录缺省 ⇒ 不再同引用 ⇒ 服务的是目录表。
554
+ * 所以写口恰好两处:`config.ts` 的铸造点(两键同一个对象)与 `web-admin-client/apply-effective.ts` 的 `commitStaged`(只换 `model`,`envModel` 永不被写);
555
+ * 克隆模型对象、或嵌入方手搓 `ServiceConfig` 时把两键指向两只对象,这一位会被误读成「目录在服务」(拒因句选错视图、`MODEL_ID` 通告误发)。
556
+ * 源码钉(`test/served-model-route.test.ts` 的类钉)把这两处写口列成白名单。
551
557
  */
552
558
  envModel: Model;
553
559
  /** Model catalog by name (1.24): always `default` + the main model's id, plus an optional cheap model.
@@ -1101,9 +1107,9 @@ export interface ServiceConfigFlat {
1101
1107
  keyPrefix?: string;
1102
1108
  presignTtlSec?: number;
1103
1109
  };
1104
- /** (a)(clay 拍 a+c,2026-07-27)SQL 默认店的 per-blob 帽显式覆写(字节)。未设 ⇒ SqlBlobBackend
1105
- * 的方言默认(tidb=6MiB=TiDB 默认 txn-entry-size-limit 真库实测矮墙,pg=不设帽);设了 ⇒ 两方言
1106
- * 都生效(调高过 entry/packet 限的部署放宽用)。软旋钮:坏值=undefined 走默认。 */
1110
+ /** (a)(clay 拍 a+c,2026-07-27)SQL 默认店的 per-blob 帽显式覆写(字节)。未设 ⇒ `sqlBlobDefaultCapBytes`
1111
+ * 的方言默认(MySQL 协议 = 库报的单行上限与包墙 `max_allowed_packet` ÷ 2 取小;事实还没建立 6MiB = TiDB 默认 txn-entry-size-limit;
1112
+ * pg=不设帽);设了 ⇒ 两方言都生效(调高过 entry/packet 限的部署放宽用)。软旋钮:坏值=undefined 走默认。 */
1107
1113
  snapshotBlobSqlMaxBytes?: number;
1108
1114
  /** (c) 的显式逃生口:云形(mysql|pg 后端)缺 MinIO 本应 boot fail-loud(bytes-in-DB 撞包墙已两役
1109
1115
  * 实证,大字节归对象存储);`SNAPSHOT_BLOB_ALLOW_SQL_BYTES=true` 显式接受 SQL 店 + (a) 的帽
@@ -1520,14 +1526,12 @@ export interface ServiceConfigFlat {
1520
1526
  * tools for a declared `plan` itself, and no plan entry clamps the hands (only `AUTONOMY=read-only` does). */
1521
1527
  planModeEnabled: boolean;
1522
1528
  /**
1523
- * [ref]⑥(core 5.56 `Hooks.timeoutMs` 座)—— **每一只 hook 席位单次调用的时间上限**(ms)。
1524
- * `HOOKS_TIMEOUT_MS`;**缺席 = 不铸键**,由 core 自默认(600s = CC 自己的数;server 不复制上游默认)。
1529
+ * `HOOKS_TIMEOUT_MS` —— 请求 `settings.hooks` 那张 mods 注册(`settings.hooks`)每个 handler 的时间预算(ms;一个事件跑一遍本请求的钩子条目)。
1530
+ * **缺席 = 不铸键**;唯一读法 = `hooks/hook-runner.ts` 的 `settingsHooksBudgetMs`(未设 ⇒ 600000,本服务跑钩子子进程的界)。
1525
1531
  *
1526
- * 🔴 `0` 是有效值(core 契约逐字:写下零的部署说了一件事 —— 每个席位立即到期),不是「未设」;
1532
+ * 🔴 `0` 是有效值(引擎按字面:零预算,下一个定时器拍就到期),不是「未设」;
1527
1533
  * 坏值(非整数 / 负 / 超 `setTimeout` 32 位上限)**拒启**,解析见 config.ts `parseHooksTimeoutEnv`。
1528
- * 施加点 = `main.ts` 的 `deploymentHooks`(server 车道)与 `run-local.ts` 的同名记录(CLI 本地车道,
1529
- * merge-rescan 745 补折:该腿今日仅同步计数器席位、折上为防倒退)。server 车道一处施加两条腿同时
1530
- * 生效:既是 `RunnerDeps.hooks`,又是 `resolve-spec` 折进 task hooks 的部署基线。
1534
+ * 部署座的两张观察注册(拒绝计量 / 工具追踪)不读它(同步返回,用引擎缺省)。
1531
1535
  */
1532
1536
  hooksTimeoutMs?: number;
1533
1537
  /** SVC-2 (adversarial-review): the workflow_journal GC retention — the reaper purges journal rows older than
package/dist/config.d.ts CHANGED
@@ -229,7 +229,7 @@ export declare function parseEnvNameAllowlist(knob: RunnerEnvNameAllowlistKnob):
229
229
  * Shared by the env lane (main + cheap models) and the center lane (web-admin toModel). */
230
230
  export declare function applyAutoCompactWindow(m: Model, explicit?: number): "explicit" | "sonnet5" | "removed-1m" | "removed";
231
231
  /**
232
- * **严格名册布防**的唯一判据(boot 就绪门 `boot/web-admin.ts` 与 S-623 端点判据同调这一只)。
232
+ * **严格名册布防**的唯一判据(boot 就绪门 `boot/web-admin.ts` 与装配第 2 段的路由端点判官同调这一只)。
233
233
  *
234
234
  * 布防 = 远程 registry ∧ 非 dryRun ∧ `CONFIG_REQUIRE_ROSTER=true`(严格 `"true"`,直读 env、不进 ServiceConfig —— 纯
235
235
  * boot 期姿势旋钮,原判据逐字搬来,零语义变化)。布防时运维声明 env MODEL_ID 是**占位**:名册落地前计费提交 503、
@@ -332,7 +332,7 @@ export declare function unmatchableToolNamesRefusal(source: string, names: reado
332
332
  * 7.117.0(core 7.42.0)起这张表整份投 `RunnerDeps.allowedTools`(引擎 allow 层的部署成员,构造时读一次),判据是**引擎的读法**,与请求的两张
333
333
  * allow 表同一份(`rule-entry-list.ts`):
334
334
  * ① 值不是字符串表 ⇒ 拒(env 的 CSV 恒给字符串表;判在这里是为了「值一旦换了来源,第一道判仍在」);
335
- * ② 引擎读成空的条目(`compileAllowList(names, "allow", 名册 = 空集).inert` 非空 —— `*`、`mcp__*`、写路径 / 域名形、带空白或畸形的名字,以及
335
+ * ② 引擎读成空的条目(`compileAllowList(names, "allow", 名册).inert` 非空 —— `*`、`mcp__*`、写路径 / 域名形、带空白或畸形的名字,以及
336
336
  * core 7.43.0 起条目名过引擎判官读成 `tool_name` 的退役名 / 无前缀短名 / 对端段铸不出,core 7.48.0 #1400 起含工具段为空的 `mcp__<srv>__`;
337
337
  * 7.116.0–7.122.x 那一形由本仓先拒,随之退役)⇒ 拒,句子点名条目、引擎给的原因词(名字层带判词与现名)、
338
338
  * 该怎么写。请求的 allow 侧对 ② 只收通告;运维这一侧拒启:这是运维自己的配置,写错了当场改,而引擎对读成空的部署条目只在每一跑发一条通告。