@sema-agent/server 7.123.0 → 7.124.1
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 +138 -0
- package/README.md +2 -2
- package/README.zh-CN.md +2 -2
- package/USAGE.md +53 -51
- 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.js +1 -1
- 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 +1 -1
- 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} +38 -22
- 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 +15 -15
- 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 +26 -6
- package/dist/config-lkg.js +43 -14
- package/dist/config-provider.d.ts +23 -19
- package/dist/config-provider.js +24 -26
- package/dist/config-types.d.ts +52 -51
- package/dist/config.d.ts +9 -46
- package/dist/config.js +33 -92
- 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 +8 -8
- 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 +7 -7
- package/dist/fleet-client.js +5 -4
- 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 +2 -2
- package/dist/http/durable-run-leg.js +2 -1
- package/dist/http/health-self-report.d.ts +4 -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 +5 -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 +1 -1
- 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.js +3 -2
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/key-resolver.d.ts +1 -1
- package/dist/leader/wire.d.ts +2 -2
- 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 +3 -3
- package/dist/model-entry-refusal.js +4 -4
- package/dist/model-provider.d.ts +2 -2
- package/dist/model-route-endpoint.d.ts +1 -1
- 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/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 +26 -2
- package/dist/plugins/scheduler-support.d.ts +26 -7
- package/dist/plugins/scheduler-support.js +96 -53
- 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/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/run-local.js +6 -3
- package/dist/runtime-caps-resolver.d.ts +4 -4
- package/dist/runtime-caps-resolver.js +2 -2
- package/dist/runtime-governance.d.ts +5 -5
- 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-titler.d.ts +0 -11
- package/dist/session-titler.js +3 -5
- package/dist/shared-memory-scope-authorizer.d.ts +4 -4
- package/dist/task-a2a.d.ts +1 -1
- 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 +17 -15
- package/dist/trace/self-minted-wire.d.ts +134 -3
- package/dist/trace/self-minted-wire.js +46 -9
- 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 +100 -119
- 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 +12 -12
- 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/{config-center → web-admin-client}/read-warnings.d.ts +23 -16
- package/dist/{config-center → web-admin-client}/read-warnings.js +33 -23
- 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 +12 -39
- package/package.json +2 -2
- package/skills/find-skills.md +2 -2
- 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
package/dist/config-lkg.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import { type MigrationReceipt } from "@sema-agent/settings-schema/one-time-migrations";
|
|
2
|
+
/** 落盘信封。`effective`/`etag` 逐字=当时的 fetchEffective 返回(JSON verbatim 面)。`formatVersion` 的语义见头注(4 = 载荷是 settings-schema 11 的形)。 */
|
|
2
3
|
export interface PersistedLkg {
|
|
3
|
-
formatVersion:
|
|
4
|
+
formatVersion: 4;
|
|
4
5
|
savedAt: string;
|
|
5
6
|
worker: string;
|
|
6
7
|
/** 拉到这份候选时所用凭证的身份(`center-credential.ts`;摘要形,不含凭证原文)。 */
|
|
@@ -46,19 +47,38 @@ export declare function lkgReadDenyRows(configLkgPath: string | undefined): {
|
|
|
46
47
|
/** 原子落盘一个干净候选(tmp+rename,0600)。BEST-EFFORT:失败=一条 warn 的素材(调用方发),绝不
|
|
47
48
|
* 影响在飞的应用链——LKG 缓存丢失的代价只是下次冷启动回到 env 兜底。 */
|
|
48
49
|
export declare function saveLkg(path: string, worker: string | undefined, identity: string, effective: Record<string, unknown>, etag: string | undefined): Promise<void>;
|
|
50
|
+
/** 一次读回做过的一次性迁移(调用方响亮打一行 `config_lkg_migrated`,并按 4 写回原位):`fromFormat` = 盘上的版本号;`note` = 信封层的说明
|
|
51
|
+
* (2 → 3 那一步,{@link migrateV2Lkg});`receipts` = 载荷层 settings-schema 迁移的收据(只点名坐标与处置,不带值)。 */
|
|
52
|
+
export interface LkgReadMigration {
|
|
53
|
+
readonly fromFormat: 2 | 3 | 4;
|
|
54
|
+
readonly note?: string;
|
|
55
|
+
readonly receipts: readonly MigrationReceipt[];
|
|
56
|
+
}
|
|
49
57
|
/**
|
|
50
58
|
* 读盘上 LKG。返回 undefined 的所有情形都「安静地回 env 兜底」(调用方 warn 点名 reason):
|
|
51
59
|
* 文件缺席/JSON 坏/信封形不对/worker 或凭证身份不匹配(防同名文件跨 worker / 跨账号串包;`CONFIG_LKG_PATH`
|
|
52
|
-
* 单一路径时这是唯一的一道)/prompts 面复判失败。
|
|
53
|
-
* `migrated`:读回时做过一次性迁移(
|
|
60
|
+
* 单一路径时这是唯一的一道)/载荷有迁不动的旧形({@link migrateLkgPayload})/prompts 面复判失败。
|
|
61
|
+
* `migrated`:读回时做过一次性迁移(信封 2 → 3 或载荷的 settings-schema 迁移)—— 调用方响亮打一行,并把交回的 4 写回原位。
|
|
54
62
|
*/
|
|
55
63
|
export declare function loadLkg(path: string, worker: string | undefined, identity: string): Promise<{
|
|
56
64
|
lkg: PersistedLkg;
|
|
57
|
-
migrated?:
|
|
65
|
+
migrated?: LkgReadMigration;
|
|
58
66
|
} | {
|
|
59
67
|
lkg?: undefined;
|
|
60
68
|
reason: string;
|
|
61
69
|
}>;
|
|
70
|
+
/**
|
|
71
|
+
* LKG 载荷(一份冻结的 effective)→ settings-schema 11 的形:调契约的 `migrateEffectiveSnapshot`(本仓不写任何一条改写规则;只认形、幂等,
|
|
72
|
+
* `version` / `updatedAt` 与其余信封键原样)。有收据 `refused`(迁不动 —— 例:同一份文档里 `atModelAllowlist` 与 `atMention` 并存、
|
|
73
|
+
* `runtime` 文档读不进)⇒ 交回拒因(**点名迁移 id 与契约的拒句**,不带值),调用方不读回这份 LKG:本仓应用 LKG 不经契约读腿,迁不动的旧形
|
|
74
|
+
* 留在载荷里就会被下游当作缺席静默略过(例:`atModelAllowlist` 不再有读者 = 限制被静默放宽)。
|
|
75
|
+
*/
|
|
76
|
+
export declare function migrateLkgPayload(effective: Record<string, unknown>): {
|
|
77
|
+
effective: Record<string, unknown>;
|
|
78
|
+
receipts: readonly MigrationReceipt[];
|
|
79
|
+
} | {
|
|
80
|
+
refused: string;
|
|
81
|
+
};
|
|
62
82
|
/** 7.98.0 及以前的默认 LKG 路径(按当时的写法逐字保留 —— 这是盘上已有文件的名字,不是现行分箱规则)。 */
|
|
63
83
|
export declare function legacyV1LkgPath(config: {
|
|
64
84
|
readonly agentConfigDir?: string;
|
|
@@ -84,7 +104,7 @@ export type LegacyLkgMigration = {
|
|
|
84
104
|
* 2. 旧文件没有(ENOENT / ENOTDIR)或不是 formatVersion 1 信封 ⇒ `none`。旧默认路径上却读不了 / 不是 JSON ⇒
|
|
85
105
|
* `not-migrated`(响亮,不当它不存在);`CONFIG_LKG_PATH` 同路径时这两形由 loadLkg 自己报(不重复打一行)。
|
|
86
106
|
* 3. v1 信封只记 worker:唯一推得出身份的形是拉取令牌(身份 = worker,`pullTokenIdentity`)。此刻身份正是它、worker
|
|
87
|
-
* 对得上、载荷过 {@link lkgPayloadProblem} ⇒ **先写后退役**(修复验证 N9):先按新格式把它写进 `binPath`(原子写,
|
|
107
|
+
* 对得上、载荷过 {@link migrateLkgPayload}(迁成 11 的形;迁不动 ⇒ 响亮拒、不写箱)与 {@link lkgPayloadProblem} ⇒ **先写后退役**(修复验证 N9):先按新格式把它写进 `binPath`(原子写,
|
|
88
108
|
* 0600),写成了才把旧文件改名 `<legacyPath>.migrated-v1`。写失败 ⇒ `not-migrated`,旧文件原样留在原位,下一次
|
|
89
109
|
* 照常可迁;写成之后改名失败 ⇒ 仍是 `migrated`(`retireError` 响一行),箱已在 ⇒ 下一次按判序 1 不再看旧文件。
|
|
90
110
|
* 同路径(`CONFIG_LKG_PATH`)时新箱的写入会原子替换旧文件本身,所以旧字节在写之前留一份 `.migrated-v1` 副本
|
package/dist/config-lkg.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { promises as fs } from "node:fs";
|
|
2
|
+
import { migrateEffectiveSnapshot } from "@sema-agent/settings-schema/one-time-migrations";
|
|
3
|
+
import { formatConfigPath } from "@sema-agent/settings-schema";
|
|
2
4
|
import { join, dirname, resolve } from "node:path";
|
|
3
5
|
import { randomBytes } from "node:crypto";
|
|
4
6
|
import { validatePromptsDomain } from "./prompts-domain-validate.js";
|
|
@@ -25,7 +27,7 @@ export function lkgReadDenyRows(configLkgPath) {
|
|
|
25
27
|
return [{ pattern: configLkgPath, caseSensitive: false }];
|
|
26
28
|
}
|
|
27
29
|
export async function saveLkg(path, worker, identity, effective, etag) {
|
|
28
|
-
const body = { formatVersion:
|
|
30
|
+
const body = { formatVersion: 4, savedAt: new Date().toISOString(), worker: worker ?? "global", identity, ...(etag !== undefined ? { etag } : {}), effective };
|
|
29
31
|
const tmp = `${path}.${randomBytes(6).toString("hex")}.tmp`;
|
|
30
32
|
await fs.mkdir(dirname(path), { recursive: true });
|
|
31
33
|
await fs.writeFile(tmp, JSON.stringify(body), { mode: 0o600 });
|
|
@@ -52,16 +54,44 @@ export async function loadLkg(path, worker, identity) {
|
|
|
52
54
|
const formatVersion = p.formatVersion;
|
|
53
55
|
if (formatVersion === 1)
|
|
54
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" };
|
|
55
|
-
if (formatVersion !== 2 && formatVersion !== 3)
|
|
57
|
+
if (formatVersion !== 2 && formatVersion !== 3 && formatVersion !== 4)
|
|
56
58
|
return { reason: `unknown formatVersion ${String(formatVersion)}` };
|
|
57
59
|
if (typeof p.worker !== "string" || p.worker !== (worker ?? "global"))
|
|
58
60
|
return { reason: `worker mismatch (file=${String(p.worker)})` };
|
|
59
61
|
if (typeof p.identity !== "string" || p.identity !== identity)
|
|
60
62
|
return { reason: "credential identity mismatch (the LKG was fetched under another credential identity — not read back)" };
|
|
61
|
-
|
|
63
|
+
if (p.effective === null || typeof p.effective !== "object" || Array.isArray(p.effective))
|
|
64
|
+
return { reason: "bad effective" };
|
|
65
|
+
let envelope = p;
|
|
66
|
+
let note;
|
|
67
|
+
if (formatVersion === 2) {
|
|
68
|
+
const v2 = migrateV2Lkg(envelope);
|
|
69
|
+
if (v2.lkg === undefined)
|
|
70
|
+
return v2;
|
|
71
|
+
envelope = v2.lkg;
|
|
72
|
+
note = v2.migrated;
|
|
73
|
+
}
|
|
74
|
+
const payload = migrateLkgPayload(envelope.effective);
|
|
75
|
+
if ("refused" in payload)
|
|
76
|
+
return { reason: payload.refused };
|
|
77
|
+
const problem = lkgPayloadProblem(payload.effective, envelope.etag);
|
|
62
78
|
if (problem !== undefined)
|
|
63
79
|
return { reason: problem };
|
|
64
|
-
|
|
80
|
+
const lkg = { ...envelope, formatVersion: 4, effective: payload.effective };
|
|
81
|
+
const migrated = formatVersion !== 4 || payload.receipts.length > 0;
|
|
82
|
+
return migrated ? { lkg, migrated: { fromFormat: formatVersion, ...(note !== undefined ? { note } : {}), receipts: payload.receipts } } : { lkg };
|
|
83
|
+
}
|
|
84
|
+
export function migrateLkgPayload(effective) {
|
|
85
|
+
const m = migrateEffectiveSnapshot(effective);
|
|
86
|
+
const refused = m.receipts.filter((r) => r.appliedAs === "refused");
|
|
87
|
+
if (refused.length > 0) {
|
|
88
|
+
return {
|
|
89
|
+
refused: "settings-schema one-time migration refused part of this LKG's payload (" +
|
|
90
|
+
refused.map((r) => `${r.migration} ${r.document}:${formatConfigPath(r.path)} — ${r.reason}`).join("; ") +
|
|
91
|
+
") — not read back: the engine applies an LKG without the contract's reader, so a form the migration cannot rewrite would be silently skipped; the next clean candidate rewrites it",
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return { effective: m.effective, receipts: m.receipts };
|
|
65
95
|
}
|
|
66
96
|
const RETIRED_CATALOG_COORDINATE = /^models\.(0|[1-9][0-9]*)$/;
|
|
67
97
|
function migrateDroppedIdentityRow(row) {
|
|
@@ -87,7 +117,7 @@ function migrateV2Lkg(lkg) {
|
|
|
87
117
|
effective = { ...lkg.effective, models: { ...rest, droppedCatalogEntries: Array.isArray(retired) ? retired.map(migrateDroppedIdentityRow) : retired } };
|
|
88
118
|
}
|
|
89
119
|
return {
|
|
90
|
-
lkg: { ...envelope,
|
|
120
|
+
lkg: { ...envelope, effective },
|
|
91
121
|
migrated: "formatVersion 2 → 3 (one-time): this LKG was written before every dropped catalog entry was recorded, so its etag is not reused — the next pull re-reads the whole candidate and re-mints the full record" +
|
|
92
122
|
(hasRetired ? "; the retired carrier models.droppedIdentities was moved to models.droppedCatalogEntries" : ""),
|
|
93
123
|
};
|
|
@@ -100,7 +130,7 @@ function lkgPayloadProblem(effective, etag) {
|
|
|
100
130
|
const eff = effective;
|
|
101
131
|
if (typeof eff.version !== "number")
|
|
102
132
|
return "bad effective.version";
|
|
103
|
-
for (const [domain, arrayKey] of [["models", "models"], ["skills", "skills"], ["mcp", "servers"], ["scenarios", "scenarios"], ["
|
|
133
|
+
for (const [domain, arrayKey] of [["models", "models"], ["skills", "skills"], ["mcp", "servers"], ["scenarios", "scenarios"], ["limits", null]]) {
|
|
104
134
|
const v = eff[domain];
|
|
105
135
|
if (v === undefined)
|
|
106
136
|
continue;
|
|
@@ -112,12 +142,6 @@ function lkgPayloadProblem(effective, etag) {
|
|
|
112
142
|
return `bad effective.${domain}.${arrayKey}`;
|
|
113
143
|
}
|
|
114
144
|
}
|
|
115
|
-
{
|
|
116
|
-
const rt = eff.runtime;
|
|
117
|
-
if (rt && (rt.autonomy !== undefined || rt.commandPolicy !== undefined || rt.approvalRequire !== undefined)) {
|
|
118
|
-
return "legacy runtime governance keys (pre-0.7.1 mirror shape; no contract producer since LKG shipped) — refusing rather than silently dropping governance";
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
145
|
const promptsRaw = eff.prompts;
|
|
122
146
|
if (promptsRaw !== undefined && !validatePromptsDomain(promptsRaw).ok)
|
|
123
147
|
return "prompts face fails re-validation";
|
|
@@ -168,7 +192,12 @@ export async function migrateV1Lkg(o) {
|
|
|
168
192
|
if (o.identity !== pullTokenIdentity(o.worker)) {
|
|
169
193
|
return refuse("its envelope records only the worker, and only a pull-token credential's identity (= the worker) can be derived from that — the current credential is not this worker's pull token, so the file cannot prove whose credential fetched it");
|
|
170
194
|
}
|
|
171
|
-
|
|
195
|
+
if (v1.effective === null || typeof v1.effective !== "object" || Array.isArray(v1.effective))
|
|
196
|
+
return refuse("its payload is unusable (bad effective)");
|
|
197
|
+
const payload = migrateLkgPayload(v1.effective);
|
|
198
|
+
if ("refused" in payload)
|
|
199
|
+
return refuse(`its payload cannot be migrated to the current settings form (${payload.refused})`);
|
|
200
|
+
const problem = lkgPayloadProblem(payload.effective, v1.etag);
|
|
172
201
|
if (problem !== undefined)
|
|
173
202
|
return refuse(`its payload is unusable (${problem})`);
|
|
174
203
|
const retiredTo = `${o.legacyPath}.migrated-v1`;
|
|
@@ -182,7 +211,7 @@ export async function migrateV1Lkg(o) {
|
|
|
182
211
|
}
|
|
183
212
|
}
|
|
184
213
|
try {
|
|
185
|
-
await saveLkg(o.binPath, o.worker, o.identity,
|
|
214
|
+
await saveLkg(o.binPath, o.worker, o.identity, payload.effective, undefined);
|
|
186
215
|
}
|
|
187
216
|
catch (err) {
|
|
188
217
|
return refuse(`writing it into this credential identity's bin failed (${String(err)}) — the old file is left in place and the migration retries on the next LKG read`);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { type DroppedConfigEntry } from "./
|
|
1
|
+
import { type DroppedConfigEntry } 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
|
-
import { fetchEffective as remoteFetchEffective, fetchSkillContent as remoteFetchSkillContent, type EffectiveConfig } from "./
|
|
5
|
-
import type { CenterEndpoint } from "./
|
|
4
|
+
import { fetchEffective as remoteFetchEffective, fetchSkillContent as remoteFetchSkillContent, type EffectiveConfig } from "./web-admin-client/facade.js";
|
|
5
|
+
import type { CenterEndpoint } from "./web-admin-client/center-request.js";
|
|
6
6
|
import type { ConfigProviderWord } from "./config-types.js";
|
|
7
|
-
/** Result of a `fetchEffective` — EXACTLY the
|
|
7
|
+
/** Result of a `fetchEffective` — EXACTLY the web-admin's return: the effective config + its etag, or
|
|
8
8
|
* `null` for "unchanged" (remote 304; local: the version matched the caller's prior etag).
|
|
9
9
|
* `domainErrors`([ref] registry-core 0.10.12 tolerant seam,local lane only):catalog 域坏文件不再
|
|
10
10
|
* 连坐全包回落 env——坏域按该域 schema default 落+错误单列,好域照常生效;caller(main.ts)对每条打
|
|
@@ -13,10 +13,8 @@ import type { ConfigProviderWord } from "./config-types.js";
|
|
|
13
13
|
/** 壳写在 `config.d/models.json` 条目上的装饰键(`sema*`)自 settings-schema 1.5.0 起是**声明过的扩展命名空间**
|
|
14
14
|
* (`EXTENSION_NAMESPACES`):schema 照旧 strip、但不再报「未知键」,所以本函数收到的每一个未知键都是拼错/越界 ⇒ 候选门错误。
|
|
15
15
|
* 此前把这类键当「通知」放行的整套下游机制(域豁免/键路径闭集/满额特判/单独的通知面)已全部撤回——意图在声明处说,消费方不猜。 */
|
|
16
|
-
/** `readWarnings`:契约 `onWarning` 流的**原值**(未折叠)
|
|
17
|
-
* `
|
|
18
|
-
* 兼容臂还开着,而契约铸出 `legacy-governance-lifted` 的理由正是「关窗的前提是有人知道它还开着」
|
|
19
|
-
* (`legacyGovernanceFromRuntime` SUNSET 注)。恒在场(空数组 = 这次读零告警),不用缺席表达「没有」
|
|
16
|
+
/** `readWarnings`:契约 `onWarning` 流的**原值**(未折叠),两条读腿同键同义 —— 读者是一致性门的读腿适配器(它要逐条对契约语料的
|
|
17
|
+
* 告警多重集,折叠后的诊断面带不回 `kind` / 坐标段)。恒在场(空数组 = 这次读零告警),不用缺席表达「没有」
|
|
20
18
|
* ——缺席/空两形并存就是又一处二义。
|
|
21
19
|
* 🔐 原流的 `error` 未经 {@link redactConfigError}(那道脱敏挂在真正进日志流的 `domainErrors` 产出边界上),
|
|
22
20
|
* 路由进日志/审计流的消费者必须自己先脱敏。 */
|
|
@@ -52,6 +50,12 @@ export type FetchEffectiveResult = {
|
|
|
52
50
|
* 不回声值(上游 settings-schema)。
|
|
53
51
|
*/
|
|
54
52
|
export declare function redactConfigError(text: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* 一个配置值的单向短指纹(`#` + 8 位十六进制;HMAC 的钥匙每进程一把 —— 只在同一条日志流里可对照,不是一份可查字典的摘要)。
|
|
55
|
+
* 句子由契约从**结构化操作数**铸的地方(settings-schema 11 的 `renderRefIssue(issue, show)`)把它当 `show` 传进去:值逐个换成指纹,
|
|
56
|
+
* 句子的固定词与坐标原样 —— 不需要 {@link redactConfigError} 那种从引号猜值边界的读法。
|
|
57
|
+
*/
|
|
58
|
+
export declare function fingerprintConfigOperand(operand: string): string;
|
|
55
59
|
/** Sentinel returned by {@link raceBootFetch} when the boot pull outlived its budget — the caller
|
|
56
60
|
* starts serving on the env fallback and the SAME promise settles in the background (never cancelled). */
|
|
57
61
|
export declare const BOOT_FETCH_DEFERRED: unique symbol;
|
|
@@ -71,7 +75,7 @@ export declare function raceBootFetch<T>(fetch: Promise<T>, budgetMs: number): P
|
|
|
71
75
|
* et al. (main.ts does not swap on this seam yet — see the NOT-YET-WIRED note at the top of this module).
|
|
72
76
|
*/
|
|
73
77
|
export interface ConfigProvider {
|
|
74
|
-
/** "remote" =
|
|
78
|
+
/** "remote" = web-admin HTTP; "local" = on-disk FileConfigStore. */
|
|
75
79
|
readonly kind: "remote" | "local";
|
|
76
80
|
/**
|
|
77
81
|
* Pull the effective config. `etag` is the caller's last-seen version token (`if-none-match` on remote;
|
|
@@ -90,10 +94,10 @@ export interface ConfigProvider {
|
|
|
90
94
|
/** The config-provider knobs read off ServiceConfig (a structural subset — avoids importing the whole
|
|
91
95
|
* ServiceConfig type and keeps this module testable with a plain object). */
|
|
92
96
|
export interface ConfigProviderInput {
|
|
93
|
-
/** Set when
|
|
97
|
+
/** Set when SEMA_WEB_ADMIN_URL is configured (config.ts `webAdmin`). `dryRun` is carried through so a
|
|
94
98
|
* remote↔local swap via this seam does NOT drop the dry-run posture main.ts branches on (config.ts
|
|
95
|
-
* `
|
|
96
|
-
|
|
99
|
+
* `webAdmin.dryRun`); the provider itself does not consume it (the caller still branches on it). */
|
|
100
|
+
webAdmin?: CenterEndpoint & {
|
|
97
101
|
worker?: string;
|
|
98
102
|
dryRun?: boolean;
|
|
99
103
|
};
|
|
@@ -108,10 +112,10 @@ export interface ConfigProviderInput {
|
|
|
108
112
|
localDir: string;
|
|
109
113
|
}
|
|
110
114
|
/**
|
|
111
|
-
* RemoteConfigProvider — DELEGATES to the exported
|
|
115
|
+
* RemoteConfigProvider — DELEGATES to the exported web-admin HTTP functions. No HTTP is reimplemented;
|
|
112
116
|
* the center endpoint (baseUrl + credential SOURCE — S-651: read per request, never a bound token) and worker
|
|
113
117
|
* are passed through. The two delegate fns are injectable (defaulting
|
|
114
|
-
* to the real
|
|
118
|
+
* to the real web-admin exports) so a unit test can assert delegation without module-mocking.
|
|
115
119
|
*/
|
|
116
120
|
export declare class RemoteConfigProvider implements ConfigProvider {
|
|
117
121
|
private readonly cc;
|
|
@@ -156,7 +160,7 @@ export declare class LocalConfigProvider implements ConfigProvider {
|
|
|
156
160
|
export declare function mapToServiceEffective(eff: AgentConfigEffective, version: number): EffectiveConfig;
|
|
157
161
|
/**
|
|
158
162
|
* Pick the backend off a CLOSED `provider` enum (`local` | `remote` | undefined): LOCAL when
|
|
159
|
-
* `CONFIG_PROVIDER=local`, OR when no
|
|
163
|
+
* `CONFIG_PROVIDER=local`, OR when no web-admin URL is configured (a lone box with config.d/ on disk
|
|
160
164
|
* and no control plane). REMOTE otherwise (a configured center URL, the default fleet posture). A
|
|
161
165
|
* `CONFIG_PROVIDER=remote` with no URL is a misconfiguration — we fall through to local rather than
|
|
162
166
|
* constructing a remote provider with no endpoint (the caller would have skipped the remote pull entirely
|
|
@@ -168,7 +172,7 @@ export declare function mapToServiceEffective(eff: AgentConfigEffective, version
|
|
|
168
172
|
export declare function createConfigProvider(input: ConfigProviderInput): ConfigProvider;
|
|
169
173
|
/**
|
|
170
174
|
* S-841 —— **本地配置根的唯一来源**:`CONFIG_LOCAL_DIR` → `AGENT_DATA_DIR` → `~/.ai-agent`。两个入口(HTTP 服务的第 1 段、
|
|
171
|
-
* run-local)各调一次,算出来的那一个值同时交给
|
|
175
|
+
* run-local)各调一次,算出来的那一个值同时交给 web-admin 工厂(`createConfigProvider` 的 `localDir`)与执行车道合成步
|
|
172
176
|
* (`composeExecutionLane` 的 `localRoot`)—— 修前两个入口各写一份这条链(run-local 还多一个与之等价的三元),工厂又在
|
|
173
177
|
* 字面 `"local"` 之外回落 `process.cwd()`。
|
|
174
178
|
*
|
|
@@ -185,14 +189,14 @@ export declare function configLocalRoot(config: {
|
|
|
185
189
|
*/
|
|
186
190
|
export declare function configProviderKind(input: {
|
|
187
191
|
readonly provider?: ConfigProviderWord | undefined;
|
|
188
|
-
readonly
|
|
192
|
+
readonly webAdmin?: unknown;
|
|
189
193
|
}): "local" | "remote";
|
|
190
194
|
/**
|
|
191
|
-
* HTTP 服务这一侧的配置源:
|
|
195
|
+
* HTTP 服务这一侧的配置源:web-admin 工厂**建不建** provider(`CONFIG_PROVIDER=local` 或配了中心才建)、建出来是哪一种。
|
|
192
196
|
* `undefined` = 纯 env 部署(没有配置源)。工厂与执行车道合成步读这同一只(车PI 修复轮 ①:合成步排在工厂之前)。
|
|
193
197
|
*/
|
|
194
198
|
export declare function serviceConfigSourceKind(config: {
|
|
195
199
|
readonly configProvider?: ConfigProviderWord | undefined;
|
|
196
|
-
readonly
|
|
200
|
+
readonly webAdmin?: unknown;
|
|
197
201
|
}): "local" | "remote" | undefined;
|
|
198
202
|
//# sourceMappingURL=config-provider.d.ts.map
|
package/dist/config-provider.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { readMcpSourceLabel } from "./mcp-source-label.js";
|
|
2
2
|
import { createHmac, randomBytes } from "node:crypto";
|
|
3
|
-
import { splitFoldedReadWarnings, withDroppedCatalogEntries } from "./
|
|
3
|
+
import { splitFoldedReadWarnings, withDroppedCatalogEntries } from "./web-admin-client/read-warnings.js";
|
|
4
4
|
import { FileConfigStore } from "@sema-agent/settings-schema/node";
|
|
5
|
-
import {
|
|
5
|
+
import { danglingRefs, findSkillContent, renderRefIssue, skillContentHash, } from "@sema-agent/settings-schema";
|
|
6
6
|
import { redactSecrets } from "./trace/redact.js";
|
|
7
|
-
import { fetchEffective as remoteFetchEffective, fetchSkillContent as remoteFetchSkillContent,
|
|
7
|
+
import { fetchEffective as remoteFetchEffective, fetchSkillContent as remoteFetchSkillContent, WebAdminHttpError, } from "./web-admin-client/facade.js";
|
|
8
8
|
import { homedir } from "node:os";
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
const OPERAND_FINGERPRINT_KEY = randomBytes(16);
|
|
@@ -14,12 +14,16 @@ export function redactConfigError(text) {
|
|
|
14
14
|
if (first === -1)
|
|
15
15
|
return s;
|
|
16
16
|
const count = (q) => s.split(q).length - 1;
|
|
17
|
-
const fingerprint = (operand) => `"
|
|
17
|
+
const fingerprint = (operand) => `"${fingerprintConfigOperand(operand)}"`;
|
|
18
18
|
if (count('"') % 2 === 1 || count("'") % 2 === 1)
|
|
19
19
|
return `${s.slice(0, first)}${fingerprint(s.slice(first + 1))}`;
|
|
20
20
|
const last = Math.max(s.lastIndexOf('"'), s.lastIndexOf("'"));
|
|
21
21
|
return `${s.slice(0, first)}${fingerprint(s.slice(first + 1, last))}${s.slice(last + 1)}`;
|
|
22
22
|
}
|
|
23
|
+
export function fingerprintConfigOperand(operand) {
|
|
24
|
+
return `#${createHmac("sha256", OPERAND_FINGERPRINT_KEY).update(operand).digest("hex").slice(0, 8)}`;
|
|
25
|
+
}
|
|
26
|
+
const redactDroppedEntry = (d) => ({ ...d, error: redactSecrets(d.error) });
|
|
23
27
|
export const BOOT_FETCH_DEFERRED = Symbol("boot-fetch-deferred");
|
|
24
28
|
export function raceBootFetch(fetch, budgetMs) {
|
|
25
29
|
if (budgetMs <= 0)
|
|
@@ -47,7 +51,7 @@ export class RemoteConfigProvider {
|
|
|
47
51
|
return {
|
|
48
52
|
...r,
|
|
49
53
|
...(r.domainErrors !== undefined ? { domainErrors: r.domainErrors.map((de) => ({ domain: de.domain, error: redactConfigError(de.error) })) } : {}),
|
|
50
|
-
...(r.droppedEntries !== undefined ? { droppedEntries: r.droppedEntries.map(
|
|
54
|
+
...(r.droppedEntries !== undefined ? { droppedEntries: r.droppedEntries.map(redactDroppedEntry) } : {}),
|
|
51
55
|
};
|
|
52
56
|
}
|
|
53
57
|
async fetchSkillContent(contentHash) {
|
|
@@ -56,7 +60,7 @@ export class RemoteConfigProvider {
|
|
|
56
60
|
return await fn(this.cc, contentHash);
|
|
57
61
|
}
|
|
58
62
|
catch (err) {
|
|
59
|
-
if (err instanceof
|
|
63
|
+
if (err instanceof WebAdminHttpError && err.status === 404)
|
|
60
64
|
return undefined;
|
|
61
65
|
throw err;
|
|
62
66
|
}
|
|
@@ -85,15 +89,17 @@ export class LocalConfigProvider {
|
|
|
85
89
|
if (etag !== undefined && etag === tag)
|
|
86
90
|
return null;
|
|
87
91
|
const refErrors = [];
|
|
88
|
-
const
|
|
89
|
-
for (const
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
const byReferrer = new Map();
|
|
93
|
+
for (const issue of danglingRefs(eff)) {
|
|
94
|
+
const rows = byReferrer.get(issue.referrer.domain) ?? [];
|
|
95
|
+
rows.push(renderRefIssue(issue, fingerprintConfigOperand));
|
|
96
|
+
byReferrer.set(issue.referrer.domain, rows);
|
|
93
97
|
}
|
|
98
|
+
for (const [domain, rows] of byReferrer)
|
|
99
|
+
refErrors.push({ domain, error: rows.join("; ") });
|
|
94
100
|
const folded = splitFoldedReadWarnings(readWarnings);
|
|
95
101
|
const parseErrors = folded.domainErrors.map((w) => ({ domain: w.domain, error: redactConfigError(w.error) }));
|
|
96
|
-
const droppedEntries = folded.droppedEntries.map(
|
|
102
|
+
const droppedEntries = folded.droppedEntries.map(redactDroppedEntry);
|
|
97
103
|
const errors = [...domainErrors.map((de) => ({ domain: de.domain, error: redactConfigError(de.error) })), ...parseErrors, ...refErrors];
|
|
98
104
|
return {
|
|
99
105
|
effective: withDroppedCatalogEntries(mapToServiceEffective(eff, eff.version), folded.droppedCatalogEntries),
|
|
@@ -139,8 +145,7 @@ export function mapToServiceEffective(eff, version) {
|
|
|
139
145
|
enabled: m.enabled,
|
|
140
146
|
})),
|
|
141
147
|
roles: eff.models.roles ?? {},
|
|
142
|
-
|
|
143
|
-
...(eff.models.atModelAllowlist !== undefined ? { atModelAllowlist: eff.models.atModelAllowlist } : {}),
|
|
148
|
+
atMention: eff.models.atMention,
|
|
144
149
|
...(eff.models.tierGroups !== undefined ? { tierGroups: eff.models.tierGroups } : {}),
|
|
145
150
|
...(eff.models.activeTierGroup !== undefined ? { activeTierGroup: eff.models.activeTierGroup } : {}),
|
|
146
151
|
},
|
|
@@ -199,13 +204,6 @@ export function mapToServiceEffective(eff, version) {
|
|
|
199
204
|
enabled: sc.enabled,
|
|
200
205
|
})),
|
|
201
206
|
},
|
|
202
|
-
runtime: {
|
|
203
|
-
...(eff.runtime.rateLimitPerMin !== undefined ? { rateLimitPerMin: eff.runtime.rateLimitPerMin } : {}),
|
|
204
|
-
...(eff.runtime.maxTaskCostUsd !== undefined ? { maxTaskCostUsd: eff.runtime.maxTaskCostUsd } : {}),
|
|
205
|
-
...(eff.runtime.maxTaskTokens !== undefined ? { maxTaskTokens: eff.runtime.maxTaskTokens } : {}),
|
|
206
|
-
...(eff.runtime.maxPrincipalCostUsd !== undefined ? { maxPrincipalCostUsd: eff.runtime.maxPrincipalCostUsd } : {}),
|
|
207
|
-
...(eff.runtime.costQuotaWindowSec !== undefined ? { costQuotaWindowSec: eff.runtime.costQuotaWindowSec } : {}),
|
|
208
|
-
},
|
|
209
207
|
...(eff.limits !== undefined ? { limits: eff.limits } : {}),
|
|
210
208
|
governance: {
|
|
211
209
|
...(eff.governance.autonomy !== undefined ? { autonomy: eff.governance.autonomy } : {}),
|
|
@@ -215,21 +213,21 @@ export function mapToServiceEffective(eff, version) {
|
|
|
215
213
|
};
|
|
216
214
|
}
|
|
217
215
|
export function createConfigProvider(input) {
|
|
218
|
-
return configProviderKind(input) === "remote" && input.
|
|
219
|
-
? new RemoteConfigProvider(input.
|
|
216
|
+
return configProviderKind(input) === "remote" && input.webAdmin !== undefined
|
|
217
|
+
? new RemoteConfigProvider(input.webAdmin)
|
|
220
218
|
: new LocalConfigProvider(input.localDir);
|
|
221
219
|
}
|
|
222
220
|
export function configLocalRoot(config) {
|
|
223
221
|
return config.configLocalDir ?? process.env.AGENT_DATA_DIR ?? join(homedir(), ".ai-agent");
|
|
224
222
|
}
|
|
225
223
|
export function configProviderKind(input) {
|
|
226
|
-
if (input.provider === "local" || input.
|
|
224
|
+
if (input.provider === "local" || input.webAdmin === undefined)
|
|
227
225
|
return "local";
|
|
228
226
|
return "remote";
|
|
229
227
|
}
|
|
230
228
|
export function serviceConfigSourceKind(config) {
|
|
231
|
-
if (config.
|
|
229
|
+
if (config.webAdmin === undefined && config.configProvider !== "local")
|
|
232
230
|
return undefined;
|
|
233
|
-
return configProviderKind({ provider: config.configProvider,
|
|
231
|
+
return configProviderKind({ provider: config.configProvider, webAdmin: config.webAdmin });
|
|
234
232
|
}
|
|
235
233
|
//# sourceMappingURL=config-provider.js.map
|