@sema-agent/server 7.122.0 → 7.124.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/MIGRATION.md +209 -0
- package/README.md +7 -2
- package/README.zh-CN.md +5 -2
- package/USAGE.md +76 -56
- package/dist/approval-ask-audit-store.d.ts +27 -32
- package/dist/approval-ask-audit-store.js +10 -9
- package/dist/approval-crash-convergence.d.ts +2 -2
- package/dist/approval-crash-convergence.js +5 -5
- package/dist/approval-deny-reasons.d.ts +163 -51
- package/dist/approval-deny-reasons.js +79 -8
- package/dist/approval-policy-settlement.d.ts +4 -1
- package/dist/approval-policy-settlement.js +3 -2
- package/dist/approval-reconciler.d.ts +3 -3
- package/dist/approval-reconciler.js +10 -10
- package/dist/approval.d.ts +1 -1
- package/dist/approval.js +1 -1
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +53 -23
- package/dist/auth-bridge.d.ts +8 -8
- package/dist/auth-bridge.js +6 -6
- package/dist/auth-keys.d.ts +2 -2
- package/dist/auto-mode-face.d.ts +13 -9
- package/dist/auto-mode-face.js +8 -7
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/execution-env.js +1 -0
- package/dist/boot/leader.d.ts +1 -1
- package/dist/boot/memory-consolidation.d.ts +4 -4
- package/dist/boot/org-memory.d.ts +3 -3
- package/dist/boot/org-memory.js +5 -5
- package/dist/boot/resolve-spec.js +7 -7
- package/dist/boot/runner-deps.d.ts +1 -1
- package/dist/boot/runtime-caps.d.ts +1 -1
- package/dist/boot/runtime-caps.js +10 -10
- package/dist/boot/shutdown.d.ts +2 -2
- package/dist/boot/shutdown.js +2 -2
- package/dist/boot/side-query-lane.d.ts +3 -3
- package/dist/boot/{stage-02-registry-pull.d.ts → stage-02-web-admin-pull.d.ts} +2 -2
- package/dist/boot/{stage-02-registry-pull.js → stage-02-web-admin-pull.js} +4 -4
- package/dist/boot/stage-03-store-backend.d.ts +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-06-runners.d.ts +2 -2
- package/dist/boot/stage-06-runners.js +6 -6
- package/dist/boot/stage-07-capability-layer.d.ts +2 -2
- package/dist/boot/stage-07-capability-layer.js +6 -5
- package/dist/boot/stage-08-reapers.d.ts +3 -3
- package/dist/boot/stage-08-reapers.js +3 -3
- package/dist/boot/stage-09-leader.d.ts +3 -3
- package/dist/boot/stage-09-leader.js +7 -7
- package/dist/boot/stage-10-http-server.d.ts +3 -3
- package/dist/boot/stage-10-http-server.js +19 -19
- package/dist/boot/unpriced-ceiling-verdict.d.ts +1 -1
- package/dist/boot/{config-center.d.ts → web-admin.d.ts} +11 -11
- package/dist/boot/{config-center.js → web-admin.js} +39 -20
- package/dist/boot/webfetch-summarize-lane.d.ts +2 -2
- package/dist/brain.d.ts +1 -1
- package/dist/brain.js +1 -1
- package/dist/budget.d.ts +3 -3
- package/dist/canonical-json.d.ts +2 -2
- package/dist/capabilities/center-plugins.d.ts +1 -1
- package/dist/capabilities/center-wiring.d.ts +12 -5
- package/dist/capabilities/center-wiring.js +11 -2
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/scenarios.js +2 -2
- package/dist/capabilities/team.d.ts +1 -1
- package/dist/capabilities/tool-defer.d.ts +1 -1
- package/dist/center-credential-renewer.d.ts +1 -1
- package/dist/center-credential-renewer.js +7 -7
- package/dist/center-credential.d.ts +9 -9
- package/dist/center-credential.js +6 -6
- package/dist/config-catalog.d.ts +7 -10
- package/dist/config-catalog.js +16 -16
- package/dist/config-d-migration.d.ts +32 -0
- package/dist/config-d-migration.js +59 -0
- package/dist/config-invariants.d.ts +14 -4
- package/dist/config-invariants.js +31 -2
- package/dist/config-lkg.d.ts +34 -11
- package/dist/config-lkg.js +76 -48
- package/dist/config-provider.d.ts +26 -21
- package/dist/config-provider.js +25 -27
- package/dist/config-types.d.ts +59 -50
- package/dist/config.d.ts +17 -54
- package/dist/config.js +99 -181
- package/dist/execution-lane-caps.d.ts +1 -1
- package/dist/fleet/drain-entry.d.ts +1 -1
- package/dist/fleet/engine-signal.d.ts +61 -30
- package/dist/fleet/engine-signal.js +29 -5
- package/dist/fleet/fleet-bus.d.ts +12 -3
- package/dist/fleet/fleet-bus.js +13 -9
- package/dist/fleet/serving-lease.d.ts +3 -3
- package/dist/fleet/serving-lease.js +1 -1
- package/dist/fleet-client.d.ts +15 -13
- package/dist/fleet-client.js +9 -7
- package/dist/fleet-lease.d.ts +3 -3
- package/dist/fleet-lease.js +2 -2
- package/dist/host-lsp-manager.d.ts +1 -1
- package/dist/hosted-posture.d.ts +4 -4
- package/dist/http/admission.js +4 -4
- package/dist/http/checkpoint-ctx.d.ts +20 -3
- package/dist/http/checkpoint-ctx.js +13 -5
- package/dist/http/dispatch.js +7 -16
- package/dist/http/durable-run-leg.js +2 -1
- package/dist/http/health-self-report.d.ts +7 -4
- package/dist/http/health-self-report.js +3 -3
- package/dist/http/idempotency.d.ts +1 -1
- package/dist/http/resume-legs.d.ts +4 -3
- package/dist/http/resume-legs.js +31 -18
- package/dist/http/route-ctx.d.ts +8 -0
- package/dist/http/routes/admin-config-refresh.d.ts +1 -1
- package/dist/http/routes/admin-config-refresh.js +1 -1
- package/dist/http/routes/admin-drain.d.ts +1 -1
- package/dist/http/routes/admin-drain.js +5 -4
- package/dist/http/routes/approvals-assistant.js +4 -4
- package/dist/http/routes/capabilities.js +6 -5
- package/dist/http/routes/config-catalog.js +2 -3
- package/dist/http/routes/diagnostics.js +1 -1
- package/dist/http/routes/runs.js +8 -4
- package/dist/http/routes/sessions-list.js +2 -1
- package/dist/http/routes/sessions.js +2 -5
- package/dist/http/routes/side-query.js +3 -3
- package/dist/http/routes/tasks.js +3 -2
- package/dist/http/run-meta.d.ts +1 -1
- package/dist/http/run-meta.js +2 -2
- package/dist/http/server.d.ts +7 -7
- package/dist/http/server.js +1 -1
- package/dist/http/stored-body-replay.d.ts +4 -3
- package/dist/http/stored-body-replay.js +5 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/key-resolver.d.ts +1 -1
- package/dist/leader/leader.d.ts +7 -6
- package/dist/leader/leader.js +3 -1
- package/dist/leader/run-entry.d.ts +2 -2
- package/dist/leader/run-entry.js +3 -3
- package/dist/leader/wire.d.ts +4 -4
- package/dist/leader/wire.js +2 -1
- package/dist/main.js +1 -1
- package/dist/mcp-tool-faces.d.ts +2 -2
- package/dist/model-entry-refusal.d.ts +20 -11
- package/dist/model-entry-refusal.js +22 -17
- package/dist/model-provider.d.ts +2 -2
- package/dist/model-route-endpoint.d.ts +22 -2
- package/dist/model-route-endpoint.js +9 -3
- package/dist/model-route-gap.d.ts +103 -0
- package/dist/model-route-gap.js +80 -0
- package/dist/model-route-url.d.ts +1 -1
- package/dist/model-route-url.js +2 -1
- package/dist/model-select.d.ts +24 -21
- package/dist/model-select.js +22 -17
- package/dist/namespaced-rule-name.d.ts +16 -30
- package/dist/namespaced-rule-name.js +2 -20
- package/dist/observability/fail-open.d.ts +0 -4
- package/dist/observability/fail-open.js +0 -4
- package/dist/observability/metrics.d.ts +1 -1
- package/dist/org-memory-admission.d.ts +1 -1
- package/dist/plugins/approval-ask-store-file.d.ts +4 -2
- package/dist/plugins/approval-ask-store-file.js +3 -3
- package/dist/plugins/approval-ask-store-memory.d.ts +4 -3
- package/dist/plugins/approval-ask-store-memory.js +10 -4
- package/dist/plugins/approval-ask-store-sql.d.ts +16 -2
- package/dist/plugins/approval-ask-store-sql.js +20 -13
- package/dist/plugins/caching-session-store.d.ts +0 -10
- package/dist/plugins/caching-session-store.js +0 -3
- package/dist/plugins/file-run-store.js +9 -3
- package/dist/plugins/leader-run-store-sql.d.ts +3 -2
- package/dist/plugins/leader-run-store-sql.js +3 -2
- package/dist/plugins/local-session-store.d.ts +20 -27
- package/dist/plugins/local-session-store.js +19 -17
- package/dist/plugins/memory-run-store.js +9 -3
- package/dist/plugins/one-time-migrations.js +51 -0
- package/dist/plugins/scheduler-support.d.ts +26 -7
- package/dist/plugins/scheduler-support.js +96 -53
- package/dist/plugins/session-policy-store-sql.js +1 -2
- package/dist/plugins/store-backend.js +1 -1
- package/dist/plugins/store-contracts.d.ts +20 -4
- package/dist/plugins/web-search.d.ts +1 -1
- package/dist/plugins/web-search.js +2 -1
- package/dist/plugins/workflow-run-store-sql.d.ts +4 -2
- package/dist/posture-source.d.ts +1 -1
- package/dist/read-face-posture.d.ts +3 -3
- package/dist/read-face-posture.js +1 -1
- package/dist/rule-entry-list.d.ts +3 -13
- package/dist/rule-entry-list.js +1 -12
- package/dist/run-local.js +10 -7
- package/dist/runtime-caps-resolver.d.ts +4 -4
- package/dist/runtime-caps-resolver.js +2 -2
- package/dist/runtime-governance.d.ts +36 -13
- package/dist/runtime-governance.js +7 -2
- package/dist/sealed-key.d.ts +4 -4
- package/dist/sealed-key.js +3 -2
- package/dist/security.d.ts +3 -3
- package/dist/service-version.d.ts +1 -1
- package/dist/service-version.js +5 -0
- package/dist/session-policy-wire.d.ts +47 -49
- package/dist/session-policy-wire.js +41 -36
- package/dist/session-sync.d.ts +5 -1
- package/dist/session-sync.js +2 -1
- package/dist/session-titler.d.ts +0 -11
- package/dist/session-titler.js +3 -5
- package/dist/shared-memory-scope-authorizer.d.ts +4 -4
- package/dist/spec-fields.d.ts +4 -4
- package/dist/spec-fields.js +1 -4
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-settings.d.ts +4 -5
- package/dist/task-settings.js +5 -8
- package/dist/tool-approval.d.ts +43 -4
- package/dist/tool-approval.js +147 -98
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/project.d.ts +3 -3
- package/dist/trace/redact.d.ts +2 -23
- package/dist/trace/redact.js +1 -6
- package/dist/trace/self-minted-wire.d.ts +147 -3
- package/dist/trace/self-minted-wire.js +50 -9
- package/dist/unattended-permission-mode.d.ts +3 -3
- package/dist/unattended-permission-mode.js +2 -2
- package/dist/url-refusal.d.ts +35 -0
- package/dist/url-refusal.js +15 -0
- package/dist/user-authored-text.d.ts +31 -0
- package/dist/user-authored-text.js +18 -0
- package/dist/{config-center → web-admin-client}/apply-effective.d.ts +13 -70
- package/dist/{config-center → web-admin-client}/apply-effective.js +104 -121
- package/dist/{config-center → web-admin-client}/apply-ledger.d.ts +2 -2
- package/dist/{config-center → web-admin-client}/center-request.d.ts +7 -7
- package/dist/{config-center → web-admin-client}/center-request.js +5 -4
- package/dist/{config-center → web-admin-client}/effective-keys.d.ts +1 -3
- package/dist/{config-center → web-admin-client}/effective-keys.js +0 -9
- package/dist/{config-center → web-admin-client}/facade.d.ts +6 -6
- package/dist/{config-center → web-admin-client}/facade.js +2 -2
- package/dist/{config-center → web-admin-client}/http-client.d.ts +6 -10
- package/dist/{config-center → web-admin-client}/http-client.js +15 -15
- package/dist/{config-center → web-admin-client}/pull-state.d.ts +1 -1
- package/dist/{config-center → web-admin-client}/read-face.js +4 -4
- package/dist/web-admin-client/read-warnings.d.ts +137 -0
- package/dist/web-admin-client/read-warnings.js +168 -0
- package/dist/{config-center → web-admin-client}/restart-signal.d.ts +5 -3
- package/dist/{config-center → web-admin-client}/restart-signal.js +3 -4
- package/dist/{config-center → web-admin-client}/skills-mcp.d.ts +1 -1
- package/dist/{config-center → web-admin-client}/skills-mcp.js +13 -13
- package/dist/{config-center → web-admin-client}/stage-limits.d.ts +1 -7
- package/dist/{config-center → web-admin-client}/stage-limits.js +6 -7
- package/dist/{config-center → web-admin-client}/types.d.ts +19 -47
- package/package.json +3 -3
- package/skills/find-skills.md +2 -2
- package/dist/config-center/read-warnings.d.ts +0 -109
- package/dist/config-center/read-warnings.js +0 -110
- package/dist/url-shape.d.ts +0 -31
- package/dist/url-shape.js +0 -41
- /package/dist/{config-center → web-admin-client}/apply-ledger.js +0 -0
- /package/dist/{config-center → web-admin-client}/hot-keys-registry.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/hot-keys-registry.js +0 -0
- /package/dist/{config-center → web-admin-client}/mcp-revocation.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/mcp-revocation.js +0 -0
- /package/dist/{config-center → web-admin-client}/pull-state.js +0 -0
- /package/dist/{config-center → web-admin-client}/read-face.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/types.js +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Web-admin adapter — pull the effective config from the web-admin control plane and
|
|
3
3
|
* apply it OVER the env-derived defaults (env = fallback, center = override). Follows the
|
|
4
4
|
* "universal internal schema → translate at the boundary" pattern, with our security boundary kept:
|
|
5
5
|
*
|
|
6
6
|
* (name history: this module tracks the control plane's product name, which has changed over time
|
|
7
7
|
* — registry → sema-web → sema-web-admin (2026-08-26 repo/product rename; an earlier revision of
|
|
8
8
|
* this note listed "planned sema-admin" as the next step). The module itself keeps a neutral, product-name-free
|
|
9
|
-
* identifier ("
|
|
9
|
+
* identifier ("web-admin") and does not chase the rename.)
|
|
10
10
|
*
|
|
11
11
|
* - the CENTER owns the LOGICAL config: the model roster (names/capabilities/tier), the role map,
|
|
12
12
|
* and collab (multi-agent discussion) templates;
|
|
@@ -41,14 +41,14 @@
|
|
|
41
41
|
* (`governance.approvalRequire` left this list in S-668 波 2 — its own staged group, hot on both legs.)
|
|
42
42
|
*
|
|
43
43
|
* ([ref] A13, internal-lossless) This module is now a FACADE: the implementation lives
|
|
44
|
-
* alongside it in `src/
|
|
44
|
+
* alongside it in `src/web-admin-client/` split by responsibility group (HTTP client / EffectiveConfig
|
|
45
45
|
* application / restart-signal detection / skills+MCP consumption). Every symbol below is
|
|
46
|
-
* re-exported UNCHANGED — existing `from ".../
|
|
46
|
+
* re-exported UNCHANGED — existing `from ".../web-admin-client/facade.js"` imports need zero changes
|
|
47
47
|
* across a rename of this file's *contents*; a path rename (this move, 2026-07-29) does require the
|
|
48
48
|
* importers to update, which was done in the same commit.
|
|
49
49
|
*/
|
|
50
|
-
export { fetchEffective, fetchPrincipalCaps, fetchPrincipalOrgMemory,
|
|
51
|
-
export { mutateInPlace, applyEffective, type ApplyReport, applyRuntimeGates, applyRuntimeHot,
|
|
50
|
+
export { fetchEffective, fetchPrincipalCaps, fetchPrincipalOrgMemory, WebAdminHttpError, fetchSkillContent, fetchPromptArtifact, fetchPromptBlob, } from "./http-client.js";
|
|
51
|
+
export { mutateInPlace, applyEffective, type ApplyReport, applyRuntimeGates, applyRuntimeHot, logEffectiveDiff, MODEL_PLANE_DOMAINS, type ModelPlaneDomain, type ModelPlaneOf, withModelPlaneOf, fullyLandedForLkg, } from "./apply-effective.js";
|
|
52
52
|
export { restartReasons, modelPlaneChanged, type RestartSlice, type RestartSliceCtx, type EngineRestartSignal, } from "./restart-signal.js";
|
|
53
53
|
export { applyCenterSkills, resolveMcpServers, mcpForScenario, resolveA2aPeers, a2aForScenario } from "./skills-mcp.js";
|
|
54
54
|
export { applyCenterReadFace, CENTER_READ_FACE_LIVE_KEYS, type CenterReadFaceApply, type CenterReadFaceReport, type ReadFaceBaseline } from "./read-face.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { fetchEffective, fetchPrincipalCaps, fetchPrincipalOrgMemory,
|
|
2
|
-
export { mutateInPlace, applyEffective, applyRuntimeGates, applyRuntimeHot,
|
|
1
|
+
export { fetchEffective, fetchPrincipalCaps, fetchPrincipalOrgMemory, WebAdminHttpError, fetchSkillContent, fetchPromptArtifact, fetchPromptBlob, } from "./http-client.js";
|
|
2
|
+
export { mutateInPlace, applyEffective, applyRuntimeGates, applyRuntimeHot, logEffectiveDiff, MODEL_PLANE_DOMAINS, withModelPlaneOf, fullyLandedForLkg, } from "./apply-effective.js";
|
|
3
3
|
export { restartReasons, modelPlaneChanged, } from "./restart-signal.js";
|
|
4
4
|
export { applyCenterSkills, resolveMcpServers, mcpForScenario, resolveA2aPeers, a2aForScenario } from "./skills-mcp.js";
|
|
5
5
|
export { applyCenterReadFace, CENTER_READ_FACE_LIVE_KEYS } from "./read-face.js";
|
|
@@ -9,11 +9,7 @@ import { type CenterEndpoint } from "./center-request.js";
|
|
|
9
9
|
* boot/refresh 的候选门直接消费。`droppedEntries`(S-704 ②):schema 逐条丢掉的条目(坐标 + 字段诊断)——
|
|
10
10
|
* **不**进候选门,调用方响亮点名、其余照用(分面单点 `splitFoldedReadWarnings`,与本地腿同一只)。
|
|
11
11
|
*
|
|
12
|
-
* `readWarnings`:契约 `onWarning` 流的**原值**(未折叠)
|
|
13
|
-
* `hosts-grandfathered` / `legacy-governance-lifted` 两员按律折成 `null`(值已被收编接受,见
|
|
14
|
-
* `read-warnings.ts` 头注),于是只看 `domainErrors` 的人**永远**看不见兼容臂有没有开着;而契约把
|
|
15
|
-
* `legacy-governance-lifted` 铸出来,理由逐字写在 `legacyGovernanceFromRuntime` 的 SUNSET 注里:
|
|
16
|
-
* 「关窗的前提是有人知道它还开着」。两条读腿各返一份原流,那句话在本仓才成立。
|
|
12
|
+
* `readWarnings`:契约 `onWarning` 流的**原值**(未折叠),与本地腿同键同义(读者:一致性门的读腿适配器,见本地腿同名键注)。
|
|
17
13
|
* 🔐 原流的 `error` 字段**未经** `redactConfigError`(那道脱敏挂在真正进日志流的 `domainErrors` 产出边界上)
|
|
18
14
|
* —— 任何把本键路由进结构化日志/审计流的消费者必须自己先脱敏。
|
|
19
15
|
*
|
|
@@ -36,12 +32,12 @@ export declare function fetchEffective(center: CenterEndpoint, etag: string | un
|
|
|
36
32
|
* Center pre-resolves the tighten-only intersection (fleet defaults ∩ tier ⊕ roles + overrides) and returns a
|
|
37
33
|
* `runtimeCaps` block — the service passes it through verbatim (no further tightening, per center's ruling).
|
|
38
34
|
*
|
|
39
|
-
* 🔐 TOKEN/WORKER (center ruling,
|
|
35
|
+
* 🔐 TOKEN/WORKER (center ruling, web-admin `aeb4979`): two valid postures —
|
|
40
36
|
* • FULL `SERVICE_PULL_TOKEN` + `?principal=` → full per-user body (caps + per-user config).
|
|
41
37
|
* • worker-scoped `wpt_<self>` + `?principal=&worker=<self>` → **caps-only** body (`{principal, configured,
|
|
42
38
|
* runtimeCaps, budget}`; never other tenants' config) — a worker MAY resolve its OWN worker's principals.
|
|
43
39
|
* A `wpt_` with NO `?worker=` (or a mismatched worker) still 403s. So we ALWAYS pass `?worker=` when the
|
|
44
|
-
* deployment has one (`
|
|
40
|
+
* deployment has one (`SEMA_WEB_ADMIN_WORKER`): it authorizes the wpt_ path AND is harmless on the full token
|
|
45
41
|
* (the caps value is worker-independent — `resolveEntitlement` resolves from the principal alone; worker only
|
|
46
42
|
* scopes the config view we ignore). This re-adds the `worker` arg dropped in 1.14.0 (L2-3) — center's ruling
|
|
47
43
|
* makes it load-bearing for AUTHORIZATION, not for the caps value.
|
|
@@ -77,9 +73,9 @@ export declare function fetchPrincipalCaps(center: CenterEndpoint, principal: st
|
|
|
77
73
|
* 因此 304 在传输层就是 fail-loud。
|
|
78
74
|
*/
|
|
79
75
|
export declare function fetchPrincipalOrgMemory(center: CenterEndpoint, principal: string, fetchImpl?: typeof fetch, worker?: string): Promise<unknown>;
|
|
80
|
-
/** An HTTP error from a
|
|
76
|
+
/** An HTTP error from a web-admin fetch that carries the response status so callers can branch on it
|
|
81
77
|
* (e.g. translate a 404 to "unknown hash → undefined") WITHOUT parsing the message string. */
|
|
82
|
-
export declare class
|
|
78
|
+
export declare class WebAdminHttpError extends Error {
|
|
83
79
|
readonly status: number;
|
|
84
80
|
constructor(message: string, status: number);
|
|
85
81
|
}
|
|
@@ -87,7 +83,7 @@ export declare class ConfigCenterHttpError extends Error {
|
|
|
87
83
|
* Fetch one skill's body by content hash (`GET <content root>/skills/content/<hash>`, Bearer; the root is
|
|
88
84
|
* `/api/v1/me` for a user-JWT credential and `/api/config` otherwise — center-request.ts) and VERIFY its
|
|
89
85
|
* sha256 matches the manifest hash (integrity + rewrite check). The content is immutable per hash, so the
|
|
90
|
-
* caller caches by hash and never re-fetches an unchanged skill. Throws a {@link
|
|
86
|
+
* caller caches by hash and never re-fetches an unchanged skill. Throws a {@link WebAdminHttpError}
|
|
91
87
|
* (carrying `.status`) on an HTTP error — INCLUDING 404 — or a plain Error on hash mismatch. Callers that
|
|
92
88
|
* want "unknown hash → undefined" parity with the local backend inspect `.status === 404` and swallow it;
|
|
93
89
|
* the legacy `applyCenterSkills` path keeps treating every throw as "skip this skill, keep baseline".
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { readEffectiveWire, PrincipalCapsWire } from "@sema-agent/settings-schema";
|
|
3
3
|
import { centerPromptsFromEffective } from "../prompts-domain-validate.js";
|
|
4
|
-
import { splitFoldedReadWarnings,
|
|
4
|
+
import { splitFoldedReadWarnings, withDroppedCatalogEntries } from "./read-warnings.js";
|
|
5
5
|
import { CENTER_PULL_TIMEOUT_MS, centerFetch } from "./center-request.js";
|
|
6
6
|
import { answerStillCurrent } from "../center-credential.js";
|
|
7
7
|
export async function fetchEffective(center, etag, fetchImpl = fetch, worker) {
|
|
@@ -9,7 +9,7 @@ export async function fetchEffective(center, etag, fetchImpl = fetch, worker) {
|
|
|
9
9
|
if (res.status === 304)
|
|
10
10
|
return null;
|
|
11
11
|
if (!res.ok)
|
|
12
|
-
throw new Error(`
|
|
12
|
+
throw new Error(`web-admin HTTP ${res.status}`);
|
|
13
13
|
const warnings = [];
|
|
14
14
|
const body = await res.json();
|
|
15
15
|
const wire = readEffectiveWire(body, (w) => warnings.push(w));
|
|
@@ -18,8 +18,8 @@ export async function fetchEffective(center, etag, fetchImpl = fetch, worker) {
|
|
|
18
18
|
delete wire.prompts;
|
|
19
19
|
else
|
|
20
20
|
wire.prompts = centerPrompts;
|
|
21
|
-
const { domainErrors, droppedEntries,
|
|
22
|
-
const effective =
|
|
21
|
+
const { domainErrors, droppedEntries, droppedCatalogEntries } = splitFoldedReadWarnings(warnings);
|
|
22
|
+
const effective = withDroppedCatalogEntries(wire, droppedCatalogEntries);
|
|
23
23
|
return {
|
|
24
24
|
effective,
|
|
25
25
|
etag: res.headers.get("etag") ?? undefined,
|
|
@@ -35,7 +35,7 @@ export async function fetchPrincipalCaps(center, principal, etag, fetchImpl = fe
|
|
|
35
35
|
return null;
|
|
36
36
|
const parsedBody = PrincipalCapsWire.safeParse(raw.json);
|
|
37
37
|
if (!parsedBody.success) {
|
|
38
|
-
throw new Error(`
|
|
38
|
+
throw new Error(`web-admin principal-caps body failed schema validation: ${parsedBody.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ").slice(0, 600)}`);
|
|
39
39
|
}
|
|
40
40
|
const body = parsedBody.data;
|
|
41
41
|
assertPrincipalEcho(body.principal, principal);
|
|
@@ -79,7 +79,7 @@ export async function fetchPrincipalCaps(center, principal, etag, fetchImpl = fe
|
|
|
79
79
|
}
|
|
80
80
|
function assertPrincipalEcho(echoed, principal) {
|
|
81
81
|
if (echoed !== undefined && echoed !== principal) {
|
|
82
|
-
throw new Error(`
|
|
82
|
+
throw new Error(`web-admin principal-caps response echoes principal ${JSON.stringify(echoed)} but ${JSON.stringify(principal)} was requested — discarding the whole response`);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
async function requestPrincipalView(center, principal, etag, fetchImpl, worker) {
|
|
@@ -91,12 +91,12 @@ async function requestPrincipalView(center, principal, etag, fetchImpl, worker)
|
|
|
91
91
|
};
|
|
92
92
|
if (res.status === 304) {
|
|
93
93
|
if (!etag)
|
|
94
|
-
throw new Error("
|
|
94
|
+
throw new Error("web-admin returned 304 to a non-conditional principal-caps request");
|
|
95
95
|
stillCurrent();
|
|
96
96
|
return null;
|
|
97
97
|
}
|
|
98
98
|
if (!res.ok)
|
|
99
|
-
throw new Error(`
|
|
99
|
+
throw new Error(`web-admin principal-caps HTTP ${res.status}`);
|
|
100
100
|
const responseEtag = res.headers.get("etag");
|
|
101
101
|
const json = await res.json();
|
|
102
102
|
stillCurrent();
|
|
@@ -106,26 +106,26 @@ const PrincipalOrgMemoryEnvelope = PrincipalCapsWire.pick({ principal: true, org
|
|
|
106
106
|
export async function fetchPrincipalOrgMemory(center, principal, fetchImpl = fetch, worker) {
|
|
107
107
|
const raw = await requestPrincipalView(center, principal, undefined, fetchImpl, worker);
|
|
108
108
|
if (raw === null)
|
|
109
|
-
throw new Error("
|
|
109
|
+
throw new Error("web-admin returned 304 to a non-conditional org-directory fetch");
|
|
110
110
|
const parsed = PrincipalOrgMemoryEnvelope.safeParse(raw.json);
|
|
111
111
|
if (!parsed.success) {
|
|
112
|
-
throw new Error(`
|
|
112
|
+
throw new Error(`web-admin org-memory section failed schema validation: ${parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ").slice(0, 600)}`);
|
|
113
113
|
}
|
|
114
114
|
assertPrincipalEcho(parsed.data.principal, principal);
|
|
115
115
|
return parsed.data.orgMemory;
|
|
116
116
|
}
|
|
117
|
-
export class
|
|
117
|
+
export class WebAdminHttpError extends Error {
|
|
118
118
|
status;
|
|
119
119
|
constructor(message, status) {
|
|
120
120
|
super(message);
|
|
121
121
|
this.status = status;
|
|
122
|
-
this.name = "
|
|
122
|
+
this.name = "WebAdminHttpError";
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
export async function fetchSkillContent(center, contentHash, fetchImpl = fetch) {
|
|
126
126
|
const { res } = await centerFetch(center, { kind: "skill-content", contentHash }, { timeoutMs: CENTER_PULL_TIMEOUT_MS, fetchImpl });
|
|
127
127
|
if (!res.ok)
|
|
128
|
-
throw new
|
|
128
|
+
throw new WebAdminHttpError(`skill content HTTP ${res.status} for ${contentHash}`, res.status);
|
|
129
129
|
const content = await res.text();
|
|
130
130
|
const want = contentHash.replace(/^sha256:/, "").toLowerCase();
|
|
131
131
|
const got = createHash("sha256").update(content, "utf8").digest("hex");
|
|
@@ -136,13 +136,13 @@ export async function fetchSkillContent(center, contentHash, fetchImpl = fetch)
|
|
|
136
136
|
export async function fetchPromptArtifact(center, artifactDigest, fetchImpl = fetch) {
|
|
137
137
|
const { res } = await centerFetch(center, { kind: "prompt-artifact", digest: artifactDigest }, { timeoutMs: CENTER_PULL_TIMEOUT_MS, fetchImpl });
|
|
138
138
|
if (!res.ok)
|
|
139
|
-
throw new
|
|
139
|
+
throw new WebAdminHttpError(`prompt artifact HTTP ${res.status} for ${artifactDigest}`, res.status);
|
|
140
140
|
return await res.json();
|
|
141
141
|
}
|
|
142
142
|
export async function fetchPromptBlob(center, contentDigest, fetchImpl = fetch) {
|
|
143
143
|
const { res } = await centerFetch(center, { kind: "prompt-blob", digest: contentDigest }, { timeoutMs: CENTER_PULL_TIMEOUT_MS, fetchImpl });
|
|
144
144
|
if (!res.ok)
|
|
145
|
-
throw new
|
|
145
|
+
throw new WebAdminHttpError(`prompt blob HTTP ${res.status} for ${contentDigest}`, res.status);
|
|
146
146
|
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
147
147
|
const want = contentDigest.replace(/^sha256:/, "").toLowerCase();
|
|
148
148
|
const got = createHash("sha256").update(bytes).digest("hex");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* S-866 ②(设计稿 v1.1 §2②)—— 「这台引擎**此刻**是不是真的接着中心」的两件读数:最近一次实拉的结局(`lastPull`)与生效修订号
|
|
3
|
-
* (`effectiveRevision`)。属主 =
|
|
3
|
+
* (`effectiveRevision`)。属主 = web-admin 运行时(`boot/web-admin.ts` 的 `centerPullState()`);读者 = caps `centerWiring`。
|
|
4
4
|
*
|
|
5
5
|
* 纯叶(零值 import):词表与读面形住这里,运行时与读面两侧都从这里取型,不各写一份。
|
|
6
6
|
*/
|
|
@@ -59,7 +59,7 @@ export function applyCenterReadFace(config, eff, logger, apply = { phase: "boot"
|
|
|
59
59
|
return report();
|
|
60
60
|
}
|
|
61
61
|
if (typeof domain !== "object" || Array.isArray(domain)) {
|
|
62
|
-
logger?.warn("
|
|
62
|
+
logger?.warn("web_admin_read_face_invalid", {
|
|
63
63
|
detail: `published readFace domain must be an object with optional {face,denyPatterns,denyBuiltinTiers,denyBuiltinExclude} — got ${Array.isArray(domain) ? "array" : typeof domain}`,
|
|
64
64
|
kept: "the deployment's env READ-face posture is unchanged (refusing a malformed domain WHOLE — a half-applied read-containment posture is worse than none)",
|
|
65
65
|
});
|
|
@@ -90,7 +90,7 @@ export function applyCenterReadFace(config, eff, logger, apply = { phase: "boot"
|
|
|
90
90
|
resolveReadDenyBuiltins(builtinsArg(finalTiers, finalExclude));
|
|
91
91
|
}
|
|
92
92
|
catch (e) {
|
|
93
|
-
logger?.warn("
|
|
93
|
+
logger?.warn("web_admin_read_face_invalid", {
|
|
94
94
|
detail: e instanceof Error ? e.message : String(e),
|
|
95
95
|
kept: "the deployment's env READ-face posture is unchanged (refusing the readFace domain WHOLE — applying half of a read-containment posture would read as 'policy landed' while part of it silently did not)",
|
|
96
96
|
});
|
|
@@ -112,13 +112,13 @@ export function applyCenterReadFace(config, eff, logger, apply = { phase: "boot"
|
|
|
112
112
|
config.readDenyBuiltinExclude = staged.readDenyBuiltinExclude;
|
|
113
113
|
}
|
|
114
114
|
if (envHeld.length > 0) {
|
|
115
|
-
logger?.warn("
|
|
115
|
+
logger?.warn("web_admin_read_face_env_wins", {
|
|
116
116
|
keys: envHeld,
|
|
117
117
|
note: "this machine's explicit env READ-face keys WIN over the published readFace domain (deployment sovereignty) — the published values for these keys were NOT applied; unset the env key if the org publication should own it",
|
|
118
118
|
});
|
|
119
119
|
}
|
|
120
120
|
if (Object.keys(staged).length > 0) {
|
|
121
|
-
logger?.info("
|
|
121
|
+
logger?.info("web_admin_read_face", {
|
|
122
122
|
applied: Object.keys(staged).filter((k) => apply.phase === "boot" || KEY_MAP.some((r) => r.cfgKey === k && CENTER_READ_FACE_LIVE_KEYS.has(r.centerKey))),
|
|
123
123
|
...(staged.readFace !== undefined ? { face: staged.readFace } : {}),
|
|
124
124
|
note: apply.phase === "boot"
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `EffectiveReadWarning` → 候选门口径的**单点**折叠(本地腿 `config-provider.ts` 与远程腿 `http-client.ts` 共用;
|
|
3
|
+
* 两腿各抄一份映射正是漂移的成因——远程腿曾漏掉一次改动,版本超前的 center 多一个字段就整份远程 refresh 整拒)。
|
|
4
|
+
*
|
|
5
|
+
* **律只有一条:未知键 = 候选门错误,零特例。** 「别的写者按契约放的扩展键」(壳写在 models 条目上的 `sema*`)
|
|
6
|
+
* 不是本函数要分辨的事——那由 settings-schema 的 `EXTENSION_NAMESPACES` 在**声明处**说清(登记的键既不点名也不计数,
|
|
7
|
+
* 1.5.0 起);到了这里的每一个键都是「写了没生效」的拼错或越界,与 domain-defaulted 同级。此前本仓在下游按 kind/
|
|
8
|
+
* 按域/按键路径闭集/按 64 满额四层猜意图,每层都被下一轮复审打穿——意图只能在声明处说,消费方不猜。
|
|
9
|
+
*
|
|
10
|
+
* 截断:schema 的键列表有界(64),超界带 `truncatedFrom`(真实总数)——文案如实带上,消费方永远不把有界列表当穷举。
|
|
11
|
+
* 词表是闭集:`switch` 穷举 `kind`,schema 加新 kind 这里编译红,不会静默漏臂。
|
|
12
|
+
*
|
|
13
|
+
* **归族判据**(下游两个消费者:候选门 = 非空 ⇒ 这棵树整拒、保 LKG;逐条丢弃面 = 响亮点名、其余照用):每一种告警都是
|
|
14
|
+
* 「写了没生效」,按**失效的颗粒**分:丢的是**一条条目**(`entry-dropped`)⇒ `scope:"entry"` —— 这条条目单独不在,同域其余条目照用,
|
|
15
|
+
* 候选**不**因它整拒;丢的是一个域 / 一组键 / 一个文件 ⇒ `scope:"domain"` —— 候选门错误。(settings-schema 11 起读路径上零抬升臂:
|
|
16
|
+
* 此前「值已被收编接受」的两种告警 `hosts-grandfathered` / `legacy-governance-lifted` 随抬升臂一起退役,旧形由一次性迁移改写,
|
|
17
|
+
* 读侧遇旧形一律拒 —— 没有「不入诊断面」的那一族了。)
|
|
18
|
+
*
|
|
19
|
+
* 🔴 S-704 ②(2026-09-24,凭据轴):此前 `entry-dropped` 归「候选门错误」(settings-schema 2.0.0 提货时的归族),于是
|
|
20
|
+
* schema 的**逐条容错**在本仓的 refresh / 迟到 boot 两条腿上被**还原成整份拒** —— 目录里一条 `contextWindow:"abc"`
|
|
21
|
+
* 就让整份目录停在上一代;而上一代若还是 env(boot 拉取失败 / 超窗且无 LKG),env 模型就一直服务、env 钥匙一直被送到
|
|
22
|
+
* 网关缺省端点(红先实测:`config_candidate_rejected` + env 模型继续服务)。粒度对了规则反而更少:颗粒是条目的失效
|
|
23
|
+
* 留在条目上,只有颗粒更粗的失效才动候选。
|
|
24
|
+
*/
|
|
25
|
+
import { z } from "zod";
|
|
26
|
+
import { type DroppedEntryIdentity, type DroppedEntryReasonCode, type EffectiveReadWarning } from "@sema-agent/settings-schema";
|
|
27
|
+
/** 折叠产物:`scope` 决定消费方做什么 —— `"domain"` 进候选门(`domainErrors`),`"entry"` 进逐条丢弃面(`droppedEntries`)。 */
|
|
28
|
+
export type FoldedReadWarning = {
|
|
29
|
+
readonly scope: "domain";
|
|
30
|
+
readonly domain: string;
|
|
31
|
+
readonly error: string;
|
|
32
|
+
} | {
|
|
33
|
+
readonly scope: "entry";
|
|
34
|
+
readonly domain: string;
|
|
35
|
+
readonly entry: string;
|
|
36
|
+
readonly error: string;
|
|
37
|
+
readonly reasonCode: DroppedEntryReasonCode;
|
|
38
|
+
};
|
|
39
|
+
/** 逐条丢弃面的一行(两条读腿的 `droppedEntries` 同形,`config_entry_dropped` 日志行读它):`entry` = 被丢那条的出门形坐标(`models.1`),
|
|
40
|
+
* `error` = 哪些字段、为什么(人读),`reasonCode` = 为什么丢的**闭集词**(S-1295:settings-schema 铸、原样过境 —— 目录行的
|
|
41
|
+
* `GET /v1/models.droppedEntries[].reasonCode` 就是这同一个词,取自同一次折叠的同一行)。 */
|
|
42
|
+
export type DroppedConfigEntry = {
|
|
43
|
+
readonly domain: string;
|
|
44
|
+
readonly entry: string;
|
|
45
|
+
readonly error: string;
|
|
46
|
+
readonly reasonCode: DroppedEntryReasonCode;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* zod 形的错误 → 一行可读的字段诊断(`contextWindow: Invalid input: expected number, received string; apiKeyEnv: <契约句>`)。
|
|
50
|
+
* 每条 issue 的句子只有一只读法 {@link issueSentenceOf}、坐标只有一只写法 {@link issueCoordinateOf}(整域面 {@link describeDomainIssues} 读同两只);
|
|
51
|
+
* 坐标缺席(issue 指整条)写 `(entry)`。
|
|
52
|
+
* 读不出 issues 形 ⇒ `undefined`(调用方退回既有文案)。模型面 stage 的逐条判据、目录载体的 `issues` 与本折叠点共用这一只(一个刻度)。
|
|
53
|
+
*/
|
|
54
|
+
export declare function describeSchemaIssues(error: unknown): string | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* zod 形错误 → 坏字段的**键路径**(去重保序;`(entry)` = 整条)。与 {@link describeSchemaIssues} 同一只坐标写法({@link issueCoordinateOf}),
|
|
57
|
+
* 不含值。模型面 stage 的逐条判据(`judgeCatalogEntry`)与本折叠点的被丢条目身份共用这一只 —— 一个刻度。
|
|
58
|
+
*/
|
|
59
|
+
export declare function describeSchemaIssueFields(error: unknown): string[];
|
|
60
|
+
/** 契约句子里**值**的位置在本仓诊断面上的写法(一个洞,不回显值;句子的固定词 —— 迁移指路、词表出路、字段名 —— 原样)。 */
|
|
61
|
+
export declare const SCHEMA_OPERAND_HOLE = "\u00ABvalue\u00BB";
|
|
62
|
+
/**
|
|
63
|
+
* 整域失效(`domain-defaulted`)的诊断文案:逐条 issue `坐标: 句子`,句子读 {@link issueSentenceOf}(与逐条丢弃面同一只):带结构化操作数的契约句重铸、
|
|
64
|
+
* 操作数换成 {@link SCHEMA_OPERAND_HOLE};不带的(zod 内建句、退役键墓碑句、迁移指路)原样。读不出 issues 形 ⇒ 退回 {@link errorText}。
|
|
65
|
+
* 为什么不直接用 `error.message`:zod 4 的 message 是整份 issues 的 JSON —— 本地腿出口的引号段指纹(`redactConfigError`)会把它从第一个
|
|
66
|
+
* 引号到最后一个引号整段吞掉,契约拒句里点名的迁移 id(「旧形读写两面响亮拒、拒句点名迁移 id」)就到不了运维眼前。
|
|
67
|
+
*/
|
|
68
|
+
export declare function describeDomainIssues(error: unknown): string;
|
|
69
|
+
/** 一条读告警 → 它的诊断面(每一种都进:见文件头「归族判据」)。 */
|
|
70
|
+
export declare function foldEffectiveReadWarning(w: EffectiveReadWarning): FoldedReadWarning;
|
|
71
|
+
/**
|
|
72
|
+
* 🔴 S-712 / S-1295 —— **被丢目录条目的载体行**(载体 = `EffectiveConfig.models.droppedCatalogEntries`,读腿铸,随 effective 走 —— 盘上 LKG
|
|
73
|
+
* 从同一个对象落盘,重启从 LKG 起服时它还在)。形的**唯一定义**(型由它推出;判据按它判盘上来的行)。
|
|
74
|
+
*
|
|
75
|
+
* **规则一条:读腿把 schema 逐条丢掉的每一条目录条目(`models` 域的 `["models", <下标>]`)记一行,写入时不挑;每个读者读自己要的那一部分。**
|
|
76
|
+
* · 墓碑判据(`model-entry-refusal.ts` `judgeCatalogEntries`)—— 有名(`identity.name`)且未停用(`identity.enabled !== false`)的行;
|
|
77
|
+
* · `GET /v1/models` 的 `droppedEntries`({@link buildDroppedEntriesWire})—— 每一行的下标、闭集词与可披露身份;
|
|
78
|
+
* · `config_entry_dropped` 日志行读的是这一行由之而来的那条折叠行({@link DroppedConfigEntry},同一次折叠、同一个词)。
|
|
79
|
+
* (修前 S-712 的载体 `droppedIdentities` 在写入时只收「有名且启用」的行 —— 那是墓碑读者的筛子,装在了写入处;同一件事于是没有
|
|
80
|
+
* 第二个读者可用。筛子回到读者那里,载体就只剩「记下发生了什么」这一条律。)
|
|
81
|
+
*
|
|
82
|
+
* 🔐 不含值:`identity` 取告警自带的身份(settings-schema 只铸可披露的标识符 —— 秘密形 / 非标识符的串 ⇒ 该键缺席,三键都没有 ⇒ 整个缺席);
|
|
83
|
+
* `index` 是条目在**这次读到的那份目录文档** `models` 数组里的原下标(数,不是串);`fields` 是坏字段的键路径、`issues` 是
|
|
84
|
+
* {@link describeSchemaIssues} 的一行(键名 + 类型词)—— 后两者只供本机拒因句,不上 wire。
|
|
85
|
+
*/
|
|
86
|
+
export declare const DroppedCatalogEntryRow: z.ZodObject<{
|
|
87
|
+
index: z.ZodNumber;
|
|
88
|
+
reasonCode: z.ZodEnum<{
|
|
89
|
+
"entry-schema-invalid": "entry-schema-invalid";
|
|
90
|
+
"entry-key-invalid": "entry-key-invalid";
|
|
91
|
+
"entry-unreadable": "entry-unreadable";
|
|
92
|
+
}>;
|
|
93
|
+
identity: z.ZodOptional<z.ZodObject<{
|
|
94
|
+
name: z.ZodOptional<z.ZodString>;
|
|
95
|
+
id: z.ZodOptional<z.ZodString>;
|
|
96
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
97
|
+
}, z.core.$strict>>;
|
|
98
|
+
fields: z.ZodArray<z.ZodString>;
|
|
99
|
+
issues: z.ZodString;
|
|
100
|
+
}, z.core.$strict>;
|
|
101
|
+
export type DroppedCatalogEntry = z.infer<typeof DroppedCatalogEntryRow>;
|
|
102
|
+
/**
|
|
103
|
+
* 两条读腿(远端 `http-client.ts` / 本地 `config-provider.ts`)共用的**分面单点**:折叠产物按 `scope` 分进候选门
|
|
104
|
+
* (`domainErrors`)与逐条丢弃面(`droppedEntries`);逐条丢弃里的**目录条目**同一拍铸进目录载体(`droppedCatalogEntries`,
|
|
105
|
+
* 一次遍历、一行折叠、一个词 —— 日志行与载体行不各算一次)。`switch` 穷举 —— 加一种 scope 不补臂 = 编译红,两腿不会各分各的。
|
|
106
|
+
* 文案**未脱敏**:进日志流之前各腿在自己的产出边界上脱敏 —— `domainErrors` 过 `redactConfigError`(引号段读法);`droppedEntries` 的文案是结构化句子
|
|
107
|
+
* (键名坐标 + 类型词 + 契约整句,值位是洞)、不含配置里的值,只过 `redactSecrets`(契约句的固定词里有引号 / 撇号,引号段读法会把迁移指路整段吞掉)。
|
|
108
|
+
* 坏行本身照样走 `droppedEntries`(坐标 + 字段 + 词,不带值)。
|
|
109
|
+
*/
|
|
110
|
+
export declare function splitFoldedReadWarnings(warnings: readonly EffectiveReadWarning[]): {
|
|
111
|
+
domainErrors: Array<{
|
|
112
|
+
domain: string;
|
|
113
|
+
error: string;
|
|
114
|
+
}>;
|
|
115
|
+
droppedEntries: DroppedConfigEntry[];
|
|
116
|
+
droppedCatalogEntries: DroppedCatalogEntry[];
|
|
117
|
+
};
|
|
118
|
+
/** 把本次读交出的目录载体挂上 effective 的模型域(两腿同一只;空 ⇒ 不挂键)。 */
|
|
119
|
+
export declare function withDroppedCatalogEntries<E extends {
|
|
120
|
+
models?: object;
|
|
121
|
+
}>(effective: E, rows: readonly DroppedCatalogEntry[]): E;
|
|
122
|
+
/** `GET /v1/models` 顶层 `droppedEntries` 的一行(wire 形;契约 §A.1d「`GET /v1/models` 的 `droppedEntries`」)。 */
|
|
123
|
+
export interface DroppedEntryWireRow {
|
|
124
|
+
readonly index: number;
|
|
125
|
+
readonly reasonCode: DroppedEntryReasonCode;
|
|
126
|
+
readonly identity?: DroppedEntryIdentity;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* S-1295 —— 本代目录的被丢条目(`config.droppedCatalogEntries`)→ `GET /v1/models` 的 `droppedEntries`。纯投影,**唯一**出口。
|
|
130
|
+
* · 词:settings-schema 的闭集原样过境({@link reasonCodeForWire} 穷举:包加词 / 删词 ⇒ 本仓编译红,逼一次「这个词能不能上 wire」的显式决定);
|
|
131
|
+
* · 身份:`name` / `id` 在出口再问一次包的 `isDisclosableIdentity`(唯一判据,import 不复制)—— 载体可能来自被手改的盘上 LKG,读腿铸的身份
|
|
132
|
+
* 本来就过了同一只判据;不可披露 ⇒ 该键不出门(不打码:打过码的串不再是身份);`enabled` 是布尔照带;三键都不剩 ⇒ `identity` 缺席;
|
|
133
|
+
* · 不投 `fields` / `issues`(人读的诊断句,不是契约),不投坐标串(下标是数)。
|
|
134
|
+
* 恒返回数组(零条 = `[]`):键恒在场,缺席只意味着更早的 server。
|
|
135
|
+
*/
|
|
136
|
+
export declare function buildDroppedEntriesWire(rows: readonly DroppedCatalogEntry[]): DroppedEntryWireRow[];
|
|
137
|
+
//# sourceMappingURL=read-warnings.d.ts.map
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { DROPPED_ENTRY_REASON_CODES, formatConfigPath, isDisclosableIdentity, renderQuotedSentence, } from "@sema-agent/settings-schema";
|
|
3
|
+
export function describeSchemaIssues(error) {
|
|
4
|
+
const issues = schemaIssuesOf(error);
|
|
5
|
+
if (issues === undefined)
|
|
6
|
+
return undefined;
|
|
7
|
+
return issues
|
|
8
|
+
.map((raw) => `${issueCoordinateOf(raw) ?? "(entry)"}: ${issueSentenceOf(raw)}`)
|
|
9
|
+
.join("; ");
|
|
10
|
+
}
|
|
11
|
+
function issueCoordinateOf(raw) {
|
|
12
|
+
const p = typeof raw === "object" && raw !== null ? raw.path : undefined;
|
|
13
|
+
return Array.isArray(p) && p.length > 0 ? formatConfigPath(p) : undefined;
|
|
14
|
+
}
|
|
15
|
+
function issueSentenceOf(raw) {
|
|
16
|
+
const message = typeof raw === "object" && raw !== null ? raw.message : undefined;
|
|
17
|
+
return contractSentenceOf(raw) ?? (typeof message === "string" ? message : "(unreadable issue)");
|
|
18
|
+
}
|
|
19
|
+
function contractSentenceOf(raw) {
|
|
20
|
+
const params = (typeof raw === "object" && raw !== null ? raw.params : undefined);
|
|
21
|
+
return params !== undefined && Array.isArray(params.template) && Array.isArray(params.operands)
|
|
22
|
+
? renderQuotedSentence(params, () => SCHEMA_OPERAND_HOLE)
|
|
23
|
+
: undefined;
|
|
24
|
+
}
|
|
25
|
+
function schemaIssuesOf(error) {
|
|
26
|
+
const issues = typeof error === "object" && error !== null ? error.issues : undefined;
|
|
27
|
+
return Array.isArray(issues) && issues.length > 0 ? issues : undefined;
|
|
28
|
+
}
|
|
29
|
+
export function describeSchemaIssueFields(error) {
|
|
30
|
+
const issues = schemaIssuesOf(error) ?? [];
|
|
31
|
+
return [...new Set(issues.map((raw) => issueCoordinateOf(raw) ?? "(entry)"))];
|
|
32
|
+
}
|
|
33
|
+
const MAX_ERROR_CHARS = 600;
|
|
34
|
+
const TRUNCATED_MARK = "…(truncated)";
|
|
35
|
+
const cap = (s) => (s.length <= MAX_ERROR_CHARS ? s : `${s.slice(0, MAX_ERROR_CHARS - TRUNCATED_MARK.length)}${TRUNCATED_MARK}`);
|
|
36
|
+
const errorText = (e) => (e instanceof Error ? e.message : String(e));
|
|
37
|
+
export const SCHEMA_OPERAND_HOLE = "«value»";
|
|
38
|
+
export function describeDomainIssues(error) {
|
|
39
|
+
const issues = schemaIssuesOf(error);
|
|
40
|
+
if (issues === undefined)
|
|
41
|
+
return errorText(error);
|
|
42
|
+
return issues
|
|
43
|
+
.map((raw) => {
|
|
44
|
+
const at = issueCoordinateOf(raw);
|
|
45
|
+
const sentence = issueSentenceOf(raw);
|
|
46
|
+
return at !== undefined ? `${at}: ${sentence}` : sentence;
|
|
47
|
+
})
|
|
48
|
+
.join("; ");
|
|
49
|
+
}
|
|
50
|
+
const keyList = (prefix, keys, truncatedFrom) => {
|
|
51
|
+
const total = truncatedFrom ?? keys.length;
|
|
52
|
+
const budget = MAX_ERROR_CHARS - prefix.length;
|
|
53
|
+
const shown = [];
|
|
54
|
+
let used = 0;
|
|
55
|
+
const suffixFor = (n) => (n < total ? ` (+${total - n} more, list truncated)` : "");
|
|
56
|
+
for (const k of keys) {
|
|
57
|
+
const rendered = formatConfigPath(k);
|
|
58
|
+
const piece = (shown.length > 0 ? ", " : "") + rendered;
|
|
59
|
+
if (used + piece.length + suffixFor(shown.length + 1).length > budget)
|
|
60
|
+
break;
|
|
61
|
+
shown.push(rendered);
|
|
62
|
+
used += piece.length;
|
|
63
|
+
}
|
|
64
|
+
return `${prefix}${shown.join(", ")}${suffixFor(shown.length)}`;
|
|
65
|
+
};
|
|
66
|
+
export function foldEffectiveReadWarning(w) {
|
|
67
|
+
switch (w.kind) {
|
|
68
|
+
case "domain-defaulted":
|
|
69
|
+
return { scope: "domain", domain: w.domain, error: cap(describeDomainIssues(w.error)) };
|
|
70
|
+
case "entry-dropped":
|
|
71
|
+
return { scope: "entry", domain: w.domain, entry: formatConfigPath(w.path), error: cap(`entry dropped by domain schema: ${describeSchemaIssues(w.error) ?? errorText(w.error)}`), reasonCode: droppedReasonCodeOf(w) };
|
|
72
|
+
case "unknown-keys-dropped":
|
|
73
|
+
return { scope: "domain", domain: w.domain, error: keyList("unknown keys dropped by domain schema: ", w.keys, w.truncatedFrom) };
|
|
74
|
+
case "unknown-keys-carried":
|
|
75
|
+
return { scope: "domain", domain: w.domain, error: keyList("unknown keys carried to consumer (spelling?): ", w.keys, w.truncatedFrom) };
|
|
76
|
+
case "unread-config-file":
|
|
77
|
+
return { scope: "domain", domain: w.domain ?? "config.d", error: cap(`unread config file ${w.file} (${w.why})`) };
|
|
78
|
+
default: {
|
|
79
|
+
const never = w;
|
|
80
|
+
throw new Error(`unhandled EffectiveReadWarning kind: ${JSON.stringify(never)}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function droppedReasonCodeOf(w) {
|
|
85
|
+
if (w.reasonCode === undefined) {
|
|
86
|
+
throw new Error(`entry-dropped warning at ${formatConfigPath(w.path)} carries no reasonCode — settings-schema mints one on every dropped entry, so this warning did not come from the pinned package`);
|
|
87
|
+
}
|
|
88
|
+
return w.reasonCode;
|
|
89
|
+
}
|
|
90
|
+
export const DroppedCatalogEntryRow = z
|
|
91
|
+
.object({
|
|
92
|
+
index: z.number().int().nonnegative(),
|
|
93
|
+
reasonCode: z.enum(DROPPED_ENTRY_REASON_CODES),
|
|
94
|
+
identity: z.object({ name: z.string().optional(), id: z.string().optional(), enabled: z.boolean().optional() }).strict().optional(),
|
|
95
|
+
fields: z.array(z.string()),
|
|
96
|
+
issues: z.string(),
|
|
97
|
+
})
|
|
98
|
+
.strict();
|
|
99
|
+
function catalogIndexOf(w) {
|
|
100
|
+
return w.kind === "entry-dropped" && w.domain === "models" && w.path.length === 2 && w.path[0] === "models" && typeof w.path[1] === "number" ? w.path[1] : undefined;
|
|
101
|
+
}
|
|
102
|
+
function identityOf(i) {
|
|
103
|
+
if (i === undefined)
|
|
104
|
+
return undefined;
|
|
105
|
+
const out = { ...(i.name !== undefined ? { name: i.name } : {}), ...(i.id !== undefined ? { id: i.id } : {}), ...(i.enabled !== undefined ? { enabled: i.enabled } : {}) };
|
|
106
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
107
|
+
}
|
|
108
|
+
export function splitFoldedReadWarnings(warnings) {
|
|
109
|
+
const domainErrors = [];
|
|
110
|
+
const droppedEntries = [];
|
|
111
|
+
const droppedCatalogEntries = [];
|
|
112
|
+
for (const w of warnings) {
|
|
113
|
+
const f = foldEffectiveReadWarning(w);
|
|
114
|
+
switch (f.scope) {
|
|
115
|
+
case "domain":
|
|
116
|
+
domainErrors.push({ domain: f.domain, error: f.error });
|
|
117
|
+
break;
|
|
118
|
+
case "entry": {
|
|
119
|
+
droppedEntries.push({ domain: f.domain, entry: f.entry, error: f.error, reasonCode: f.reasonCode });
|
|
120
|
+
const index = catalogIndexOf(w);
|
|
121
|
+
if (index !== undefined && w.kind === "entry-dropped") {
|
|
122
|
+
const identity = identityOf(w.identity);
|
|
123
|
+
droppedCatalogEntries.push({ index, reasonCode: f.reasonCode, ...(identity !== undefined ? { identity } : {}), fields: describeSchemaIssueFields(w.error), issues: describeSchemaIssues(w.error) ?? "(schema issues unreadable)" });
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
default: {
|
|
128
|
+
const never = f;
|
|
129
|
+
throw new Error(`unhandled folded read-warning scope: ${JSON.stringify(never)}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return { domainErrors, droppedEntries, droppedCatalogEntries };
|
|
134
|
+
}
|
|
135
|
+
export function withDroppedCatalogEntries(effective, rows) {
|
|
136
|
+
if (rows.length === 0 || effective.models === undefined)
|
|
137
|
+
return effective;
|
|
138
|
+
return { ...effective, models: { ...effective.models, droppedCatalogEntries: [...rows] } };
|
|
139
|
+
}
|
|
140
|
+
export function buildDroppedEntriesWire(rows) {
|
|
141
|
+
return rows.map((r) => {
|
|
142
|
+
const identity = disclosableIdentityOf(r.identity);
|
|
143
|
+
return { index: r.index, reasonCode: reasonCodeForWire(r.reasonCode), ...(identity !== undefined ? { identity } : {}) };
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function reasonCodeForWire(code) {
|
|
147
|
+
switch (code) {
|
|
148
|
+
case "entry-schema-invalid":
|
|
149
|
+
case "entry-key-invalid":
|
|
150
|
+
case "entry-unreadable":
|
|
151
|
+
return code;
|
|
152
|
+
default: {
|
|
153
|
+
const never = code;
|
|
154
|
+
throw new Error(`unhandled DroppedEntryReasonCode: ${JSON.stringify(never)}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function disclosableIdentityOf(i) {
|
|
159
|
+
if (i === undefined)
|
|
160
|
+
return undefined;
|
|
161
|
+
const out = {
|
|
162
|
+
...(i.name !== undefined && isDisclosableIdentity(i.name) ? { name: i.name } : {}),
|
|
163
|
+
...(i.id !== undefined && isDisclosableIdentity(i.id) ? { id: i.id } : {}),
|
|
164
|
+
...(i.enabled !== undefined ? { enabled: i.enabled } : {}),
|
|
165
|
+
};
|
|
166
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=read-warnings.js.map
|
|
@@ -39,8 +39,8 @@ export interface RestartSliceCtx {
|
|
|
39
39
|
}
|
|
40
40
|
/** S-741(车OG):本引擎发布的重启信号。形的唯一定义是 settings-schema 6.1.0 `RestartSignal`(`{ reasons, version, since }`,在场即信号,
|
|
41
41
|
* 不夹 `restartRequired` 布尔;本地手写的那份接口已删),这里只把 `reasons` 收窄到本文件的闭集 {@link RestartSlice} —— 写口
|
|
42
|
-
* (`boot/
|
|
43
|
-
* `string[]`,闭集的编译期判据丢了)。`/health.restart` 与 fleet 心跳 `restart` 两个出口交
|
|
42
|
+
* (`boot/web-admin.ts` `publishRestart`)按它收,拼错 / 已退役的词编译红(opus 对抗腿 #2:直接用上游型时 `reasons` 是
|
|
43
|
+
* `string[]`,闭集的编译期判据丢了)。`/health.restart` 与 fleet 心跳 `restart` 两个出口交 web-admin 同一只 `restartState()`
|
|
44
44
|
* 的同一个对象,按契约形出门。 */
|
|
45
45
|
export type EngineRestartSignal = RestartSignal & {
|
|
46
46
|
reasons: RestartSlice[];
|
|
@@ -89,6 +89,8 @@ export declare function restartReasons(boot: EffectiveConfig | undefined, curren
|
|
|
89
89
|
* undefined` (env-boot plane, no EffectiveConfig to compare) is conservatively "changed": the first center plane
|
|
90
90
|
* always swaps. Not gated on tier activity: a Runner's expanded catalog goes stale on ANY plane change,
|
|
91
91
|
* including a tiers-off flip, and the default entry rides the fingerprint because the Runner's copy carries its
|
|
92
|
-
* own `default` (codex R8; SAME resolver as applyEffective —
|
|
92
|
+
* own `default` (codex R8; SAME resolver as applyEffective — settings-schema `resolveCatalogDefaultModel`, single source: a
|
|
93
|
+
* `named` default fingerprints by its name, a `{select}` default by its criteria — the engine resolves the same criteria over
|
|
94
|
+
* the same fingerprinted catalog and tier table, so equal criteria on an unchanged plane give the same entry). */
|
|
93
95
|
export declare function modelPlaneChanged(prev: EffectiveConfig | undefined, next: EffectiveConfig): boolean;
|
|
94
96
|
//# sourceMappingURL=restart-signal.d.ts.map
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { resolveActiveTiers } from "@sema-agent/settings-schema";
|
|
1
|
+
import { resolveActiveTiers, resolveCatalogDefaultModel } from "@sema-agent/settings-schema";
|
|
2
2
|
import { stableStringify } from "@sema-agent/settings-schema/hash";
|
|
3
3
|
import { DEFAULT_PLUGIN_ALLOW_HOSTS, materializablePlugins } from "../capabilities/center-plugins.js";
|
|
4
|
-
import { resolveDefaultModelName } from "./apply-effective.js";
|
|
5
4
|
import { CENTER_READ_FACE_LIVE_KEYS } from "./read-face.js";
|
|
6
5
|
const RESTART_SLICES = ["skills", "mcp", "a2a", "scenarios", "degrade-route", "read-face", "memory-consolidation"];
|
|
7
6
|
function enabledOnly(rows) {
|
|
@@ -83,8 +82,8 @@ export function modelPlaneChanged(prev, next) {
|
|
|
83
82
|
const enabled = enabledOnly(e.models?.models);
|
|
84
83
|
const active = e.models ? (resolveActiveTiers(e.models) ?? null) : null;
|
|
85
84
|
const names = new Set((enabled ?? []).map((m) => m.name));
|
|
86
|
-
const def =
|
|
87
|
-
return stableStringify({ models: planeEntriesFingerprint(e.models?.models), tiers: active, default: def.name });
|
|
85
|
+
const def = e.models ? resolveCatalogDefaultModel(e.models, (n) => names.has(n), enabled?.[0]?.name ?? "") : undefined;
|
|
86
|
+
return stableStringify({ models: planeEntriesFingerprint(e.models?.models), tiers: active, default: def === undefined ? null : def.kind === "named" ? def.name : { select: def.select } });
|
|
88
87
|
};
|
|
89
88
|
return fp(prev) !== fp(next);
|
|
90
89
|
}
|
|
@@ -5,7 +5,7 @@ import type { LoadedSkill } from "../capabilities/skills.js";
|
|
|
5
5
|
import type { CenterEndpoint } from "./center-request.js";
|
|
6
6
|
import type { CenterA2aPeer, CenterMcpServer, CenterSkillManifest } from "./types.js";
|
|
7
7
|
/**
|
|
8
|
-
* Merge center skills OVER the image baseline ([ref]-sibling B1; `
|
|
8
|
+
* Merge center skills OVER the image baseline ([ref]-sibling B1; `web-admin docs/MCP-SKILLS.md`). Load order =
|
|
9
9
|
* `loadSkills(SKILLS_DIR)` baseline → center skills lazily fetched by hash and overlaid BY NAME (center
|
|
10
10
|
* wins on a clash → can override a built-in; guarded center-side by publisher RBAC + the publish gate).
|
|
11
11
|
* `enabled:false` is skipped. Content is verified + cached by hash (same hash fetched once). A skill whose
|