@sema-agent/server 7.98.0 → 7.100.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 +19 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +86 -60
- package/deploy/sema-up/lib/envf.sh +110 -42
- package/deploy/sema-up/sema-up.sh +76 -34
- package/dist/approval-ask-machine.d.ts +10 -0
- package/dist/approval-ask-machine.js +3 -0
- package/dist/approval-card.d.ts +74 -1
- package/dist/approval-card.js +41 -8
- package/dist/approval.d.ts +44 -20
- package/dist/approval.js +14 -6
- package/dist/boot/config-center.d.ts +16 -8
- package/dist/boot/config-center.js +206 -103
- package/dist/boot/execution-env.d.ts +1 -2
- package/dist/boot/execution-env.js +2 -2
- package/dist/boot/leader.js +12 -9
- package/dist/boot/memory-consolidation.d.ts +38 -0
- package/dist/boot/memory-consolidation.js +35 -0
- package/dist/boot/org-memory.d.ts +2 -1
- package/dist/boot/org-memory.js +9 -5
- package/dist/boot/resolve-spec.d.ts +0 -1
- package/dist/boot/resolve-spec.js +4 -3
- package/dist/boot/runner-deps.d.ts +2 -2
- package/dist/boot/runtime-caps.js +4 -4
- 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 +3 -3
- package/dist/boot/stage-07-capability-layer.d.ts +2 -3
- package/dist/boot/stage-07-capability-layer.js +6 -6
- package/dist/boot/stage-08-reapers.d.ts +3 -4
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +2 -3
- package/dist/boot/stage-10-http-server.d.ts +2 -3
- package/dist/boot/stage-10-http-server.js +2 -2
- package/dist/capabilities/center-plugins.d.ts +14 -2
- package/dist/capabilities/center-plugins.js +13 -5
- package/dist/capabilities/center-prompts.d.ts +3 -0
- package/dist/capabilities/center-prompts.js +1 -1
- package/dist/capabilities/hands-lane.js +2 -1
- package/dist/capabilities/scenarios.js +18 -5
- package/dist/capabilities/tool-defer.d.ts +2 -2
- package/dist/center-credential.d.ts +112 -0
- package/dist/center-credential.js +131 -0
- package/dist/config-catalog.d.ts +2 -2
- package/dist/config-catalog.js +15 -15
- package/dist/config-center/apply-effective.d.ts +34 -39
- package/dist/config-center/apply-effective.js +100 -64
- package/dist/config-center/apply-ledger.d.ts +35 -16
- package/dist/config-center/apply-ledger.js +25 -18
- package/dist/config-center/center-request.d.ts +60 -0
- package/dist/config-center/center-request.js +71 -0
- package/dist/config-center/facade.d.ts +11 -5
- package/dist/config-center/facade.js +1 -1
- package/dist/config-center/hot-keys-registry.d.ts +11 -4
- package/dist/config-center/hot-keys-registry.js +11 -7
- package/dist/config-center/http-client.d.ts +17 -9
- package/dist/config-center/http-client.js +27 -36
- package/dist/config-center/restart-signal.d.ts +21 -14
- package/dist/config-center/restart-signal.js +16 -22
- package/dist/config-center/skills-mcp.d.ts +4 -1
- package/dist/config-center/skills-mcp.js +2 -2
- package/dist/config-center/types.d.ts +3 -3
- package/dist/config-invariants.d.ts +2 -2
- package/dist/config-invariants.js +0 -8
- package/dist/config-lkg.d.ts +47 -8
- package/dist/config-lkg.js +107 -20
- package/dist/config-provider.d.ts +8 -7
- package/dist/config-provider.js +5 -5
- package/dist/config-types.d.ts +30 -11
- package/dist/config.js +11 -13
- package/dist/cross-session-settings.js +1 -1
- package/dist/fleet-client.d.ts +8 -8
- package/dist/fleet-client.js +7 -7
- package/dist/fleet-lease.d.ts +11 -11
- package/dist/fleet-lease.js +17 -13
- package/dist/host-lsp-manager.d.ts +29 -0
- package/dist/host-lsp-manager.js +14 -0
- package/dist/hosted-posture.d.ts +49 -93
- package/dist/hosted-posture.js +1 -25
- package/dist/http/active-run-conflict.d.ts +2 -12
- package/dist/http/active-run-conflict.js +1 -6
- package/dist/http/admission.js +8 -0
- package/dist/http/resume-legs.d.ts +1 -1
- package/dist/http/resume-legs.js +14 -10
- package/dist/http/route-ctx.d.ts +2 -2
- package/dist/http/routes/approvals-assistant.d.ts +1 -1
- package/dist/http/routes/approvals-assistant.js +2 -2
- package/dist/http/routes/memory-compliance.js +5 -0
- package/dist/http/routes/memory-origin.js +5 -0
- package/dist/http/routes/sessions.js +6 -0
- package/dist/http/routes/tasks.js +7 -6
- package/dist/http/server.d.ts +6 -5
- package/dist/http/wire-types.d.ts +6 -3
- package/dist/leader/wire.d.ts +20 -12
- package/dist/leader/wire.js +7 -6
- package/dist/memory-layer-preflight.d.ts +46 -0
- package/dist/memory-layer-preflight.js +121 -0
- package/dist/memory-operator-faces.js +17 -1
- package/dist/observability/corrupt-read-seat.d.ts +21 -4
- package/dist/observability/corrupt-read-seat.js +31 -0
- package/dist/observability/fail-open.d.ts +8 -4
- package/dist/observability/fail-open.js +8 -4
- package/dist/observability/run-terminal.js +1 -0
- package/dist/observability/secret-env-scrub.d.ts +3 -26
- package/dist/observability/secret-env-scrub.js +3 -2
- package/dist/orchestration/workflow-completion-inbox.d.ts +31 -23
- package/dist/orchestration/workflow-completion-inbox.js +8 -3
- package/dist/plugins/approval-ask-store-file.d.ts +20 -2
- package/dist/plugins/approval-ask-store-file.js +21 -3
- package/dist/plugins/approval-ask-store-memory.d.ts +2 -0
- package/dist/plugins/approval-ask-store-memory.js +39 -13
- package/dist/plugins/approval-ask-store-sql.d.ts +24 -5
- package/dist/plugins/approval-ask-store-sql.js +27 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +9 -3
- package/dist/plugins/checkpoint-store-sql.js +19 -2
- package/dist/plugins/local-checkpoint-store.js +2 -0
- package/dist/plugins/mailbox-store-sql.d.ts +7 -5
- package/dist/plugins/mailbox-store-sql.js +6 -4
- package/dist/plugins/permission-rule-store-file.js +3 -2
- package/dist/plugins/remote-env-host.d.ts +3 -1
- package/dist/plugins/remote-env-host.js +3 -2
- package/dist/plugins/sql-json-column.d.ts +16 -3
- package/dist/plugins/sql-json-column.js +15 -4
- package/dist/plugins/web-search.d.ts +42 -22
- package/dist/plugins/web-search.js +141 -49
- package/dist/project-memory.d.ts +28 -1
- package/dist/project-memory.js +22 -22
- package/dist/run-local.js +6 -7
- package/dist/runs.js +6 -5
- package/dist/runtime-caps-resolver.d.ts +8 -8
- package/dist/runtime-caps-resolver.js +16 -14
- package/dist/runtime-governance.d.ts +50 -3
- package/dist/runtime-governance.js +5 -0
- package/dist/sealed-key.js +3 -7
- package/dist/server-secret-env.d.ts +43 -0
- package/dist/server-secret-env.js +18 -0
- package/dist/task-settings.d.ts +1 -1
- package/dist/tool-approval.d.ts +144 -9
- package/dist/tool-approval.js +74 -18
- package/dist/trace/core-keyset-guard.d.ts +5 -5
- package/dist/trace/ledger-sink.js +2 -2
- package/dist/trace/project.d.ts +13 -0
- package/dist/trace/project.js +22 -5
- package/dist/trace/projection-drop.d.ts +2 -0
- package/dist/trace/projection-drop.js +6 -0
- package/dist/trace/sema-provenance.d.ts +4 -1
- package/dist/trace/sema-provenance.js +1 -1
- package/dist/trace/task-notification-facets.d.ts +65 -0
- package/dist/trace/task-notification-facets.js +31 -0
- package/dist/trace/wire-projection-faces.d.ts +3 -3
- package/dist/trace/wire-projection-faces.js +3 -3
- package/package.json +5 -4
|
@@ -11,16 +11,17 @@ import { applyCatalogToSource, withPromptArtifactBackfill } from "../capabilitie
|
|
|
11
11
|
import { validatePromptsDomain, CORE_ENGINE_VERSION } from "../prompts-domain-validate.js";
|
|
12
12
|
import { centerScenarios, centerScenarioDetails } from "../capabilities/scenarios.js";
|
|
13
13
|
import { configLkgEnabled, isRosterGateArmed } from "../config.js";
|
|
14
|
-
import { defaultLkgPath, defaultSkillCacheDir, saveLkg, loadLkg } from "../config-lkg.js";
|
|
14
|
+
import { defaultLkgPath, defaultSkillCacheDir, saveLkg, loadLkg, legacyV1LkgPath, migrateV1Lkg } from "../config-lkg.js";
|
|
15
|
+
import { answerStillCurrent, centerStateBin, credentialIdentityNow } from "../center-credential.js";
|
|
15
16
|
import { centerManagedConfigKeys } from "../config-center/apply-effective.js";
|
|
16
17
|
import { createConfigProvider, raceBootFetch, BOOT_FETCH_DEFERRED } from "../config-provider.js";
|
|
17
18
|
import { executionLaneCaps, executionLaneOf } from "../execution-lane-caps.js";
|
|
18
19
|
import { createKeyResolver } from "../key-resolver.js";
|
|
19
20
|
import { ensureSealedKeyStore, reportExecutionPublicKey } from "../sealed-key.js";
|
|
20
|
-
import { applyEffective, applyCenterReadFace, mutateInPlace, logEffectiveDiff, applyCenterSkills, resolveMcpServers, resolveA2aPeers, restartReasons, modelPlaneChanged,
|
|
21
|
+
import { applyEffective, applyCenterReadFace, mutateInPlace, logEffectiveDiff, applyCenterSkills, resolveMcpServers, resolveA2aPeers, restartReasons, modelPlaneChanged, fetchPromptArtifact } from "../config-center/facade.js";
|
|
21
22
|
import { createMcpRevocationLedger, enabledMcpEntries } from "../config-center/mcp-revocation.js";
|
|
22
23
|
import { SHA256_HEX_RE } from "../digest-form.js";
|
|
23
|
-
import { createConfigApplyLedger } from "../config-center/apply-ledger.js";
|
|
24
|
+
import { createConfigApplyLedger, refusedGroups } from "../config-center/apply-ledger.js";
|
|
24
25
|
export async function createConfigCenterRuntime(ctx) {
|
|
25
26
|
const { config, logger, metrics, localRoot } = ctx;
|
|
26
27
|
let ccEtag;
|
|
@@ -53,6 +54,43 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
53
54
|
let bootSkillStale = false;
|
|
54
55
|
let pendingRestart;
|
|
55
56
|
const cc = config.configCenter;
|
|
57
|
+
const bootCredential = cc?.credential.read();
|
|
58
|
+
if (cc !== undefined && bootCredential !== undefined && !bootCredential.ok) {
|
|
59
|
+
logger.error("center_credential_unreadable", {
|
|
60
|
+
key: "SEMA_REGISTRY_TOKEN_FILE",
|
|
61
|
+
reason: bootCredential.reason,
|
|
62
|
+
effect: "every center request fails its own failure arm until the file is readable (config pull keeps env/LKG-less boot, caps fail-closed, lease takes the loud auth-error arm); no on-disk LKG / prompt state is read back (credential identity unknown)",
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
const currentIdentity = () => (cc === undefined ? undefined : credentialIdentityNow(cc.credential));
|
|
66
|
+
const candidateIdentity = new WeakMap();
|
|
67
|
+
const candidateIdentityOf = (eff) => candidateIdentity.get(eff);
|
|
68
|
+
const validatorIdentity = new Map();
|
|
69
|
+
const bindValidator = (etag, identity) => {
|
|
70
|
+
if (etag === undefined)
|
|
71
|
+
return;
|
|
72
|
+
validatorIdentity.delete(etag);
|
|
73
|
+
validatorIdentity.set(etag, identity);
|
|
74
|
+
const oldest = validatorIdentity.keys().next();
|
|
75
|
+
if (validatorIdentity.size > 16 && oldest.done !== true)
|
|
76
|
+
validatorIdentity.delete(oldest.value);
|
|
77
|
+
};
|
|
78
|
+
const pullEffective = async (provider, etag) => {
|
|
79
|
+
if (provider.kind === "local")
|
|
80
|
+
return provider.fetchEffective(etag);
|
|
81
|
+
const before = currentIdentity();
|
|
82
|
+
const conditional = etag !== undefined && before !== undefined && validatorIdentity.get(etag) === before ? etag : undefined;
|
|
83
|
+
const r = await provider.fetchEffective(conditional);
|
|
84
|
+
const used = r === null ? before : r.credentialIdentity;
|
|
85
|
+
if (cc === undefined || !answerStillCurrent(cc.credential, used)) {
|
|
86
|
+
throw new Error("center credential identity changed while the effective pull was in flight — response discarded; the next pull runs under the current credential");
|
|
87
|
+
}
|
|
88
|
+
if (r !== null) {
|
|
89
|
+
candidateIdentity.set(r.effective, used);
|
|
90
|
+
bindValidator(r.etag, used);
|
|
91
|
+
}
|
|
92
|
+
return r;
|
|
93
|
+
};
|
|
56
94
|
let sealedKeys;
|
|
57
95
|
try {
|
|
58
96
|
sealedKeys = await ensureSealedKeyStore(join(config.localDataRoot ?? localRoot, "sealed-key"), logger);
|
|
@@ -70,7 +108,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
70
108
|
const configProvider = cc || config.configProvider === "local"
|
|
71
109
|
? createConfigProvider({
|
|
72
110
|
...(config.configProvider ? { provider: config.configProvider } : {}),
|
|
73
|
-
...(cc ? { configCenter: { baseUrl: cc.baseUrl,
|
|
111
|
+
...(cc ? { configCenter: { baseUrl: cc.baseUrl, credential: cc.credential, worker: cc.worker, dryRun: cc.dryRun } } : {}),
|
|
74
112
|
...(config.configProvider === "local" ? { localDir: localRoot } : {}),
|
|
75
113
|
})
|
|
76
114
|
: undefined;
|
|
@@ -88,41 +126,106 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
88
126
|
if (!pendingCatalogFaces)
|
|
89
127
|
return;
|
|
90
128
|
const { target } = pendingCatalogFaces;
|
|
91
|
-
if (await applyCatalogToSource(
|
|
129
|
+
if (await applyCatalogToSource(catalogSource, target, centerPrompts, logger, phase)) {
|
|
92
130
|
centerPrompts = target;
|
|
93
131
|
pendingCatalogFaces = undefined;
|
|
94
132
|
}
|
|
95
133
|
};
|
|
96
134
|
const promptEpochDir = join(config.localDataRoot ?? localRoot, "prompt-epoch");
|
|
97
|
-
const
|
|
98
|
-
|
|
135
|
+
const promptStateRoot = join(promptEpochDir, "state");
|
|
136
|
+
let promptStateIdentity = currentIdentity();
|
|
137
|
+
const promptStateBin = () => (cc === undefined ? "global" : promptStateIdentity === undefined ? undefined : centerStateBin(cc.worker, promptStateIdentity));
|
|
138
|
+
const storePerBin = (make) => {
|
|
139
|
+
const stores = new Map();
|
|
140
|
+
return (bin) => {
|
|
141
|
+
const hit = stores.get(bin);
|
|
142
|
+
if (hit !== undefined)
|
|
143
|
+
return hit;
|
|
144
|
+
const made = make(bin);
|
|
145
|
+
stores.set(bin, made);
|
|
146
|
+
return made;
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
const fileStateStoreFor = storePerBin((bin) => new FilePromptSourceStateStore(join(promptStateRoot, bin)));
|
|
150
|
+
const binnedPromptStateStore = (storeFor) => ({
|
|
151
|
+
load: async () => {
|
|
152
|
+
const bin = promptStateBin();
|
|
153
|
+
return bin === undefined ? undefined : storeFor(bin).load();
|
|
154
|
+
},
|
|
155
|
+
save: async (state) => {
|
|
156
|
+
const bin = promptStateBin();
|
|
157
|
+
if (bin === undefined)
|
|
158
|
+
throw new Error("center credential identity unknown (credential unreadable at adoption) — prompt source state not persisted");
|
|
159
|
+
await storeFor(bin).save(state);
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
let promptPersisted;
|
|
163
|
+
const recordingStateStore = (inner) => ({
|
|
164
|
+
load: async () => {
|
|
165
|
+
promptPersisted = await inner.load();
|
|
166
|
+
return promptPersisted;
|
|
167
|
+
},
|
|
168
|
+
save: async (state) => {
|
|
169
|
+
await inner.save(state);
|
|
170
|
+
promptPersisted = state;
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
const withByDigestBackfill = (inner) => cc?.baseUrl ? withPromptArtifactBackfill(inner, (d) => fetchPromptArtifact(cc, d), logger) : inner;
|
|
99
174
|
const promptSource = (() => {
|
|
100
175
|
try {
|
|
176
|
+
const bootBin = promptStateBin();
|
|
177
|
+
if (bootBin !== undefined)
|
|
178
|
+
fileStateStoreFor(bootBin);
|
|
101
179
|
return new CenterPromptSource({
|
|
102
180
|
store: withByDigestBackfill(new FilePromptArtifactStore(promptEpochDir)),
|
|
103
|
-
stateStore:
|
|
181
|
+
stateStore: recordingStateStore(binnedPromptStateStore(fileStateStoreFor)),
|
|
104
182
|
engineVersion: CORE_ENGINE_VERSION,
|
|
105
183
|
});
|
|
106
184
|
}
|
|
107
185
|
catch (e) {
|
|
108
186
|
logger.warn("center_prompts_store_unwritable", { dir: promptEpochDir, err: String(e), note: "file-backed prompt-epoch store unavailable — memory fallback (catalog candidate not restart-durable); built-ins/declaration axis unaffected" });
|
|
109
|
-
return new CenterPromptSource({
|
|
187
|
+
return new CenterPromptSource({
|
|
188
|
+
store: withByDigestBackfill(new MemoryPromptArtifactStore()),
|
|
189
|
+
stateStore: recordingStateStore(binnedPromptStateStore(storePerBin(() => new MemoryPromptSourceStateStore()))),
|
|
190
|
+
engineVersion: CORE_ENGINE_VERSION,
|
|
191
|
+
});
|
|
110
192
|
}
|
|
111
193
|
})();
|
|
112
|
-
|
|
194
|
+
const catalogSource = {
|
|
195
|
+
applySnapshot: (raw) => promptSource.applySnapshot(raw),
|
|
196
|
+
applyDisabled: (sourceRevision) => promptSource.applyDisabled(sourceRevision),
|
|
197
|
+
current: () => promptSource.current(),
|
|
198
|
+
persistedActive: () => promptPersisted?.state === "active",
|
|
199
|
+
};
|
|
200
|
+
const rebasePromptState = async (identity, phase) => {
|
|
201
|
+
promptStateIdentity = identity;
|
|
202
|
+
centerPrompts = undefined;
|
|
203
|
+
pendingCatalogFaces = undefined;
|
|
204
|
+
promptPersisted = undefined;
|
|
113
205
|
try {
|
|
114
206
|
await promptSource.restore();
|
|
115
207
|
}
|
|
116
208
|
catch (e) {
|
|
117
|
-
logger.warn("center_prompts_catalog_restore_failed", { err: String(e), note: "
|
|
209
|
+
logger.warn("center_prompts_catalog_restore_failed", { phase, err: String(e), note: "the persisted catalog state for this credential identity could not be loaded — catalog candidate absent until the next adopt; declaration axis and built-ins unaffected" });
|
|
118
210
|
}
|
|
119
|
-
|
|
211
|
+
if (cc !== undefined && identity !== undefined && currentIdentity() !== identity) {
|
|
212
|
+
promptStateIdentity = undefined;
|
|
213
|
+
await promptSource.restore();
|
|
214
|
+
logger.warn("center_prompts_catalog_identity_changed", { phase, note: "the center credential changed while the persisted catalog state was being read — that state is not used; the current identity's next candidate re-establishes it" });
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
if (configProvider && !cc?.dryRun)
|
|
218
|
+
await rebasePromptState(promptStateIdentity, "boot");
|
|
120
219
|
const adoptCenterPrompts = async (eff, phase) => {
|
|
220
|
+
const adoptedIdentity = candidateIdentityOf(eff);
|
|
221
|
+
if (adoptedIdentity !== undefined && adoptedIdentity !== promptStateIdentity) {
|
|
222
|
+
await rebasePromptState(adoptedIdentity, phase);
|
|
223
|
+
}
|
|
121
224
|
const raw = eff?.prompts;
|
|
122
225
|
if (raw === undefined) {
|
|
123
226
|
if (centerPrompts)
|
|
124
227
|
logger.info("center_prompts_cleared", { phase, note: "effective carries no prompts key (publish gate off) — built-in providers resume" });
|
|
125
|
-
const cleared = await applyCatalogToSource(
|
|
228
|
+
const cleared = await applyCatalogToSource(catalogSource, undefined, centerPrompts, logger, phase);
|
|
126
229
|
if (cleared) {
|
|
127
230
|
centerPrompts = undefined;
|
|
128
231
|
pendingCatalogFaces = undefined;
|
|
@@ -148,7 +251,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
148
251
|
note: "new tasks assemble the new pack (epoch re-pins at the next task boundary); in-flight sessions stay pinned",
|
|
149
252
|
});
|
|
150
253
|
}
|
|
151
|
-
const transitioned = await applyCatalogToSource(
|
|
254
|
+
const transitioned = await applyCatalogToSource(catalogSource, v.value, centerPrompts, logger, phase);
|
|
152
255
|
if (transitioned) {
|
|
153
256
|
centerPrompts = v.value;
|
|
154
257
|
pendingCatalogFaces = undefined;
|
|
@@ -159,7 +262,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
159
262
|
};
|
|
160
263
|
let bootConfigPending;
|
|
161
264
|
const lkgEnabled = configProvider?.kind === "remote" && configLkgEnabled();
|
|
162
|
-
const
|
|
265
|
+
const lkgPathFor = (identity) => process.env.CONFIG_LKG_PATH ?? defaultLkgPath(cc?.worker, identity);
|
|
163
266
|
const lkgSurvivesRestart = lkgEnabled && process.env.CONFIG_LKG_DURABLE === "true";
|
|
164
267
|
let lkgBooted = false;
|
|
165
268
|
let bootLkgCandidate;
|
|
@@ -170,9 +273,15 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
170
273
|
return true;
|
|
171
274
|
if (!lkgEnabled)
|
|
172
275
|
return false;
|
|
276
|
+
const identity = candidateIdentityOf(effectiveObj);
|
|
277
|
+
if (identity === undefined) {
|
|
278
|
+
logger.warn("config_lkg_save_failed", { err: "candidate carries no credential identity", note: "LKG NOT written (the bin is keyed by the identity that fetched the candidate) — handoff NOT confirmed" });
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
const lkgPath = lkgPathFor(identity);
|
|
173
282
|
try {
|
|
174
283
|
if (effectiveObj.skills && config.configCenter) {
|
|
175
|
-
await applyCenterSkills([], effectiveObj.skills, config.configCenter
|
|
284
|
+
await applyCenterSkills([], effectiveObj.skills, config.configCenter, logger, undefined, defaultSkillCacheDir());
|
|
176
285
|
}
|
|
177
286
|
const enabledSkills = (effectiveObj.skills?.skills ?? []).filter((m) => m.enabled !== false);
|
|
178
287
|
const cacheDir = defaultSkillCacheDir();
|
|
@@ -193,7 +302,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
193
302
|
}
|
|
194
303
|
}
|
|
195
304
|
lastPrewarmBodiesVerified = true;
|
|
196
|
-
await saveLkg(lkgPath, cc?.worker, effectiveObj, etag);
|
|
305
|
+
await saveLkg(lkgPath, cc?.worker, identity, effectiveObj, etag);
|
|
197
306
|
return lkgSurvivesRestart;
|
|
198
307
|
}
|
|
199
308
|
catch (err) {
|
|
@@ -206,19 +315,45 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
206
315
|
const bootFromLkg = async (why) => {
|
|
207
316
|
if (!lkgEnabled || dryRun)
|
|
208
317
|
return null;
|
|
209
|
-
const
|
|
318
|
+
const identity = currentIdentity();
|
|
319
|
+
if (identity === undefined) {
|
|
320
|
+
logger.warn("config_lkg_unusable", { reason: "center credential unreadable — credential identity unknown, no LKG bin is read back", note: "env fallback serves; the live pull retries on the refresh cadence once the credential is readable" });
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
const lkgPath = lkgPathFor(identity);
|
|
324
|
+
const legacy = await migrateV1Lkg({ legacyPath: process.env.CONFIG_LKG_PATH ?? legacyV1LkgPath(cc?.worker), binPath: lkgPath, worker: cc?.worker, identity });
|
|
325
|
+
switch (legacy.outcome) {
|
|
326
|
+
case "none":
|
|
327
|
+
break;
|
|
328
|
+
case "migrated":
|
|
329
|
+
logger.info("config_lkg_migrated", { from: legacy.from, retiredTo: legacy.retiredTo, to: lkgPath, note: "formatVersion 1 LKG (pull-token identity = this worker) migrated once into this credential identity's bin; the old file was renamed, not deleted" });
|
|
330
|
+
if (legacy.retireError !== undefined)
|
|
331
|
+
logger.warn("config_lkg_legacy_not_retired", { path: legacy.from, reason: legacy.retireError, note: "the bin was written and is used; only the old file's rename / copy failed" });
|
|
332
|
+
break;
|
|
333
|
+
case "not-migrated":
|
|
334
|
+
logger.warn("config_lkg_unusable", { path: legacy.path, reason: legacy.reason, note: "env fallback serves; the cache rewrites on the next clean candidate" });
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
const read = await loadLkg(lkgPath, cc?.worker, identity);
|
|
210
338
|
if (!read.lkg) {
|
|
211
339
|
if (read.reason !== "absent")
|
|
212
340
|
logger.warn("config_lkg_unusable", { path: lkgPath, reason: read.reason, note: "ignoring the on-disk LKG — env fallback serves; the cache rewrites on the next clean candidate" });
|
|
213
341
|
return null;
|
|
214
342
|
}
|
|
343
|
+
if (currentIdentity() !== identity) {
|
|
344
|
+
logger.warn("config_lkg_unusable", { path: lkgPath, reason: "center credential identity changed while the LKG was being read — not used", note: "env fallback serves; the current identity's next pull re-establishes its own LKG" });
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
215
347
|
logger.info("config_loaded_lkg", { path: lkgPath, savedAt: read.lkg.savedAt, why, note: "booting from the persisted last-known-good (all restart-to-apply faces included) — the live pull continues in the background and reconciles on arrival" });
|
|
216
|
-
|
|
348
|
+
const lkgEffective = read.lkg.effective;
|
|
349
|
+
candidateIdentity.set(lkgEffective, identity);
|
|
350
|
+
bindValidator(read.lkg.etag, identity);
|
|
351
|
+
return { effective: lkgEffective, ...(read.lkg.etag !== undefined ? { etag: read.lkg.etag } : {}) };
|
|
217
352
|
};
|
|
218
353
|
const bootApplyLkgInline = async (lkgR) => {
|
|
219
354
|
const lkgGen = generationOf(lkgR.effective.version);
|
|
220
355
|
applyLedger.seenTarget(lkgGen, lkgR.effective.version);
|
|
221
|
-
applyEffective(config, lkgR.effective, logger, { sealedKeys, generation: lkgGen, report: (rep) => applyLedger.recordApply(rep) });
|
|
356
|
+
applyEffective(config, lkgR.effective, logger, { leg: "boot", sealedKeys, generation: lkgGen, report: (rep) => applyLedger.recordApply(rep) });
|
|
222
357
|
applyLedger.applied(lkgGen, lkgR.effective.version);
|
|
223
358
|
await adoptCenterPrompts(lkgR.effective, "boot-lkg");
|
|
224
359
|
markRosterLanded(lkgR.effective);
|
|
@@ -231,7 +366,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
231
366
|
logger.info("config_loaded", { source: "lkg", version: lkgR.effective.version, worker: cc?.worker ?? "(global)", models: cfgModels });
|
|
232
367
|
};
|
|
233
368
|
try {
|
|
234
|
-
const bootFetch = configProvider
|
|
369
|
+
const bootFetch = pullEffective(configProvider, undefined);
|
|
235
370
|
const raced = await raceBootFetch(bootFetch, config.configBootFetchBudgetMs);
|
|
236
371
|
let lkgFallback = null;
|
|
237
372
|
if (raced === BOOT_FETCH_DEFERRED) {
|
|
@@ -274,6 +409,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
274
409
|
applyLedger.seenTarget(bootGen, r.effective.version);
|
|
275
410
|
let bootReport;
|
|
276
411
|
applyEffective(config, r.effective, logger, {
|
|
412
|
+
leg: "boot",
|
|
277
413
|
sealedKeys,
|
|
278
414
|
generation: bootGen,
|
|
279
415
|
report: (rep) => {
|
|
@@ -327,6 +463,8 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
327
463
|
}
|
|
328
464
|
}
|
|
329
465
|
}
|
|
466
|
+
if (!dryRun && cc !== undefined && currentIdentity() !== promptStateIdentity)
|
|
467
|
+
await rebasePromptState(currentIdentity(), "boot-end");
|
|
330
468
|
}
|
|
331
469
|
const readFaceBaseline = { ...(config.readFace !== undefined ? { readFace: config.readFace } : {}), readFaceSource: config.readFaceSource };
|
|
332
470
|
const readFaceEnvHeld = applyCenterReadFace(config, effective ?? { version: 0, updatedAt: "", models: { models: [], roles: {} } }, effective ? logger : undefined).envHeld;
|
|
@@ -337,8 +475,10 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
337
475
|
let keyResolver;
|
|
338
476
|
const mcpRevocations = createMcpRevocationLedger((ev) => logger.info("mcp_revocation_ledger", { ...(ev.revoked.length > 0 ? { revoked: ev.revoked } : {}), ...(ev.restored.length > 0 ? { restored: ev.restored } : {}) }));
|
|
339
477
|
let mcpRevocationWired = false;
|
|
340
|
-
const restartCtx = () => ({
|
|
478
|
+
const restartCtx = (consolidationSeat) => ({
|
|
341
479
|
...(config.degrade?.reactive ? { reactiveDegradeTo: config.degrade.to } : {}),
|
|
480
|
+
pluginsAllowHosts: config.pluginsAllowHosts,
|
|
481
|
+
...(consolidationSeat !== undefined ? { consolidationSeat } : {}),
|
|
342
482
|
...(readFaceEnvHeld.length > 0 ? { readFaceEnvHeld } : {}),
|
|
343
483
|
...(mcpRevocationWired && mcpRevocations.hasBaseline() ? { mcpRevocationLive: true } : {}),
|
|
344
484
|
});
|
|
@@ -348,10 +488,6 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
348
488
|
const { faceChanged } = applyCenterReadFace(config, eff, logger, { phase: "live", baseline: readFaceBaseline });
|
|
349
489
|
if (!faceChanged)
|
|
350
490
|
return;
|
|
351
|
-
if (swap === undefined) {
|
|
352
|
-
logger.warn("read_face_swap_unwired", { face: config.readFace ?? null, phase, note: "the center's read FACE changed but no Runner swap door was wired — the value landed in config while the engine keeps the seat it booted with" });
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
491
|
try {
|
|
356
492
|
swap({ readFace: config.readFace });
|
|
357
493
|
logger.info("read_face_swapped", { from: before ?? null, to: config.readFace ?? null, phase, note: "hot seat (core swapDeps) — legs that already prepared keep the face they prepared under" });
|
|
@@ -438,7 +574,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
438
574
|
},
|
|
439
575
|
async applyCenterCapabilities(skills) {
|
|
440
576
|
if (effective?.skills && config.configCenter) {
|
|
441
|
-
skills = await applyCenterSkills(skills, effective.skills, config.configCenter
|
|
577
|
+
skills = await applyCenterSkills(skills, effective.skills, config.configCenter, logger, undefined, configLkgEnabled() ? defaultSkillCacheDir() : undefined);
|
|
442
578
|
}
|
|
443
579
|
if (effective?.plugins) {
|
|
444
580
|
const pluginOut = await applyCenterPlugins(skills, effective, {
|
|
@@ -458,7 +594,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
458
594
|
}
|
|
459
595
|
if (bootLkgCandidate && lkgEnabled) {
|
|
460
596
|
const bootPublished = await persistLkgDurable(bootLkgCandidate.effective, bootLkgCandidate.etag).catch((err) => {
|
|
461
|
-
logger.warn("config_lkg_save_failed", {
|
|
597
|
+
logger.warn("config_lkg_save_failed", { err: String(err), note: "boot LKG persist failed — retained for the per-tick retry" });
|
|
462
598
|
return false;
|
|
463
599
|
});
|
|
464
600
|
{
|
|
@@ -507,7 +643,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
507
643
|
}
|
|
508
644
|
},
|
|
509
645
|
startRefreshLoop(a) {
|
|
510
|
-
const {
|
|
646
|
+
const { pricing, limitSync, swapRunnerDeps, ceilingVerdict, consolidationSeat, checkpointStorePresent } = a;
|
|
511
647
|
if (configProvider) {
|
|
512
648
|
const ccRef = config.configCenter;
|
|
513
649
|
let refreshInFlight = false;
|
|
@@ -521,18 +657,18 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
521
657
|
metrics.inc("models_tiers_plane_deferred_stuck_total");
|
|
522
658
|
logger.warn("models_tiers_deferred_no_handoff", { version: planeDeferredNoHandoff.version, since: planeDeferredNoHandoff.since, note: "candidate still retained without a next-boot handoff — mount restart-surviving LKG storage + CONFIG_LKG_DURABLE=true, or restart manually after ensuring the candidate is re-pulled at boot" });
|
|
523
659
|
}
|
|
524
|
-
const r = arrival !== undefined ? arrival.result : await configProvider
|
|
660
|
+
const r = arrival !== undefined ? arrival.result : await pullEffective(configProvider, ccEtag);
|
|
525
661
|
if (r === null && planeDeferredNoHandoff) {
|
|
526
662
|
const skillsDebt = (planeDeferredNoHandoff.blocked ?? []).includes("skills");
|
|
527
663
|
const promoted = lkgSurvivesRestart || skillsDebt ? await persistLkgDurable(planeDeferredNoHandoff.candidate, planeDeferredNoHandoff.candidateEtag) : false;
|
|
528
|
-
const skillsProofPromotion = !promoted && !lkgSurvivesRestart && skillsDebt && lastPrewarmBodiesVerified
|
|
664
|
+
const skillsProofPromotion = !promoted && !lkgSurvivesRestart && skillsDebt && lastPrewarmBodiesVerified;
|
|
529
665
|
if (skillsProofPromotion) {
|
|
530
666
|
pendingRestart = { restartRequired: true, reasons: ["skills"], version: planeDeferredNoHandoff.version, since: Date.now() };
|
|
531
667
|
logger.info("config_boot_skill_debt_promoted", { version: planeDeferredNoHandoff.version, note: "skill bodies verified on a source-confirmed-current candidate — the withheld skills restart is now published (non-durable lane, repair proven)" });
|
|
532
668
|
planeDeferredNoHandoff = undefined;
|
|
533
669
|
}
|
|
534
670
|
else if (promoted) {
|
|
535
|
-
const promotedReasons = [...new Set(
|
|
671
|
+
const promotedReasons = [...new Set(planeDeferredNoHandoff.blocked ?? [])];
|
|
536
672
|
if (promotedReasons.length > 0) {
|
|
537
673
|
pendingRestart = { restartRequired: true, reasons: promotedReasons, version: planeDeferredNoHandoff.version, since: Date.now() };
|
|
538
674
|
}
|
|
@@ -573,18 +709,17 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
573
709
|
}
|
|
574
710
|
else {
|
|
575
711
|
const planeChanged = modelPlaneChanged(appliedPlaneEff, r.effective);
|
|
576
|
-
const planeDeferred = swapRunnerDeps === undefined && (runnerTierFrozen || planeHasActiveTiers(r.effective)) && planeChanged;
|
|
577
712
|
let applyReport;
|
|
578
713
|
const committed = applyEffective(config, r.effective, logger, {
|
|
579
|
-
|
|
714
|
+
leg: "hot",
|
|
715
|
+
checkpointStorePresent,
|
|
580
716
|
sealedKeys,
|
|
581
717
|
generation: tickGen,
|
|
582
718
|
report: (rep) => {
|
|
583
719
|
applyReport = rep;
|
|
584
720
|
applyLedger.recordApply(rep);
|
|
585
721
|
},
|
|
586
|
-
...(
|
|
587
|
-
...(swapRunnerDeps !== undefined && planeChanged ? { swapPlane: swapRunnerDeps } : {}),
|
|
722
|
+
...(planeChanged ? { swapPlane: swapRunnerDeps } : {}),
|
|
588
723
|
});
|
|
589
724
|
if (!committed)
|
|
590
725
|
return "ok";
|
|
@@ -595,57 +730,37 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
595
730
|
mcpRevocations.applyEnabledEntries(enabledMcpEntries(r.effective.mcp));
|
|
596
731
|
applyLiveReadFace(r.effective, swapRunnerDeps, "refresh");
|
|
597
732
|
applyLedger.applied(tickGen, r.effective.version);
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
}
|
|
601
|
-
else {
|
|
602
|
-
appliedPlaneEff = r.effective;
|
|
603
|
-
planeDeferredNoHandoff = undefined;
|
|
604
|
-
}
|
|
733
|
+
appliedPlaneEff = r.effective;
|
|
734
|
+
planeDeferredNoHandoff = undefined;
|
|
605
735
|
await adoptCenterPrompts(r.effective, "refresh");
|
|
606
|
-
|
|
607
|
-
markRosterLanded(r.effective);
|
|
736
|
+
markRosterLanded(r.effective);
|
|
608
737
|
const fullyApplied = applyReport?.fullyApplied !== false;
|
|
609
738
|
if (!fullyApplied) {
|
|
739
|
+
ccEtag = undefined;
|
|
740
|
+
const refused = applyReport ? refusedGroups(applyReport) : [];
|
|
610
741
|
logger.warn("config_candidate_partially_applied", {
|
|
611
742
|
version: r.effective.version,
|
|
612
|
-
rejected:
|
|
743
|
+
rejected: refused.flatMap((g) => g.keys),
|
|
744
|
+
groups: refused.map((g) => g.group),
|
|
613
745
|
note: "a group of this candidate was refused — the live config keeps serving the prior values for it; the LKG and the ETag stay on the last FULLY applied generation (this tree is re-judged next tick)",
|
|
614
746
|
});
|
|
615
747
|
return "ok";
|
|
616
748
|
}
|
|
617
749
|
const lkgPersisted = await persistLkgDurable(r.effective, r.etag);
|
|
618
|
-
const reasons = restartReasons(effective, r.effective, restartCtx());
|
|
619
|
-
if (swapRunnerDeps !== undefined) {
|
|
620
|
-
const mi = reasons.indexOf("models-tiers");
|
|
621
|
-
if (mi >= 0)
|
|
622
|
-
reasons.splice(mi, 1);
|
|
623
|
-
}
|
|
750
|
+
const reasons = restartReasons(effective, r.effective, restartCtx(consolidationSeat?.read()));
|
|
624
751
|
const skillsChangeDetected = reasons.includes("skills");
|
|
625
752
|
if (bootSkillStale && !skillsChangeDetected)
|
|
626
753
|
reasons.push("skills");
|
|
627
|
-
if (
|
|
628
|
-
if (lkgPersisted) {
|
|
629
|
-
if (!reasons.includes("models-tiers"))
|
|
630
|
-
reasons.push("models-tiers");
|
|
631
|
-
planeDeferredNoHandoff = undefined;
|
|
632
|
-
}
|
|
633
|
-
else {
|
|
634
|
-
const blocked = reasons.splice(0, reasons.length);
|
|
635
|
-
planeDeferredNoHandoff = { version: r.effective.version, since: planeDeferredNoHandoff?.since ?? Date.now(), ...(blocked.length > 0 ? { blocked } : {}), planeDeferred: true, candidate: r.effective, ...(r.etag !== undefined ? { candidateEtag: r.etag } : {}) };
|
|
636
|
-
logger.warn("models_tiers_deferred_no_handoff", { version: r.effective.version, blockedReasons: blocked, note: "plane deferred but no NEXT-BOOT handoff (LKG disabled/unwritable, or storage not declared restart-surviving — set CONFIG_LKG_DURABLE=true) — the WHOLE restart signal is withheld (it would loop); the old generation keeps serving" });
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
else if (lkgSurvivesRestart && !lkgPersisted) {
|
|
754
|
+
if (lkgSurvivesRestart && !lkgPersisted) {
|
|
640
755
|
const blocked = reasons.splice(0, reasons.length);
|
|
641
|
-
planeDeferredNoHandoff = { version: r.effective.version, since:
|
|
756
|
+
planeDeferredNoHandoff = { version: r.effective.version, since: Date.now(), blocked, candidate: r.effective, ...(r.etag !== undefined ? { candidateEtag: r.etag } : {}) };
|
|
642
757
|
logger.warn("restart_candidate_publication_incomplete", { version: r.effective.version, blockedReasons: blocked, note: "durable LKG declared but the candidate's publication is incomplete (skill bodies unverified) — restart signal withheld; retried every tick until the cache completes" });
|
|
643
758
|
}
|
|
644
|
-
else if (!
|
|
759
|
+
else if (!lkgSurvivesRestart && bootSkillStale && !skillsChangeDetected && !lastPrewarmBodiesVerified) {
|
|
645
760
|
const i = reasons.indexOf("skills");
|
|
646
761
|
if (i >= 0) {
|
|
647
762
|
reasons.splice(i, 1);
|
|
648
|
-
planeDeferredNoHandoff = { version: r.effective.version, since:
|
|
763
|
+
planeDeferredNoHandoff = { version: r.effective.version, since: Date.now(), blocked: ["skills"], candidate: r.effective, ...(r.etag !== undefined ? { candidateEtag: r.etag } : {}) };
|
|
649
764
|
logger.warn("config_boot_skill_debt_withheld", { version: r.effective.version, note: "boot skill debt still unproven on a non-durable deployment (body cache does not verify) — skills restart withheld this tick; re-verified each tick and published once the bodies prove fetchable" });
|
|
650
765
|
}
|
|
651
766
|
}
|
|
@@ -660,7 +775,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
660
775
|
}
|
|
661
776
|
logger.info("sema_registry_refreshed", {
|
|
662
777
|
version: r.effective.version,
|
|
663
|
-
note: "collab + runtime governance + limits + models/roles/roster hot-applied; skills/mcp/
|
|
778
|
+
note: "collab + runtime governance (incl. approvalRequire) + limits + models/roles/roster hot-applied; skills/mcp/a2a/scenarios are restart-to-apply",
|
|
664
779
|
...(pendingRestart ? { restartRequired: true, restartReasons: pendingRestart.reasons } : {}),
|
|
665
780
|
});
|
|
666
781
|
latestEffective = r.effective;
|
|
@@ -721,18 +836,17 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
721
836
|
return;
|
|
722
837
|
}
|
|
723
838
|
const planeChangedLate = modelPlaneChanged(appliedPlaneEff, r.effective);
|
|
724
|
-
const planeDeferredLate = swapRunnerDeps === undefined && (runnerTierFrozen || planeHasActiveTiers(r.effective)) && planeChangedLate;
|
|
725
839
|
let applyReportLate;
|
|
726
840
|
const committedLate = applyEffective(config, r.effective, logger, {
|
|
727
|
-
|
|
841
|
+
leg: "hot",
|
|
842
|
+
checkpointStorePresent,
|
|
728
843
|
sealedKeys,
|
|
729
844
|
generation: lateGen,
|
|
730
845
|
report: (rep) => {
|
|
731
846
|
applyReportLate = rep;
|
|
732
847
|
applyLedger.recordApply(rep);
|
|
733
848
|
},
|
|
734
|
-
...(
|
|
735
|
-
...(swapRunnerDeps !== undefined && planeChangedLate ? { swapPlane: swapRunnerDeps } : {}),
|
|
849
|
+
...(planeChangedLate ? { swapPlane: swapRunnerDeps } : {}),
|
|
736
850
|
});
|
|
737
851
|
if (!committedLate)
|
|
738
852
|
return;
|
|
@@ -742,20 +856,18 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
742
856
|
ceilingVerdict?.judge();
|
|
743
857
|
applyLiveReadFace(r.effective, swapRunnerDeps, "boot-deferred");
|
|
744
858
|
applyLedger.applied(lateGen, r.effective.version);
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
else {
|
|
748
|
-
appliedPlaneEff = r.effective;
|
|
749
|
-
planeDeferredNoHandoff = undefined;
|
|
750
|
-
}
|
|
859
|
+
appliedPlaneEff = r.effective;
|
|
860
|
+
planeDeferredNoHandoff = undefined;
|
|
751
861
|
await adoptCenterPrompts(r.effective, "boot-deferred");
|
|
752
|
-
|
|
753
|
-
markRosterLanded(r.effective);
|
|
862
|
+
markRosterLanded(r.effective);
|
|
754
863
|
const fullyAppliedLate = applyReportLate?.fullyApplied !== false;
|
|
755
864
|
if (!fullyAppliedLate) {
|
|
865
|
+
ccEtag = undefined;
|
|
866
|
+
const refusedLate = applyReportLate ? refusedGroups(applyReportLate) : [];
|
|
756
867
|
logger.warn("config_candidate_partially_applied", {
|
|
757
868
|
version: r.effective.version,
|
|
758
|
-
rejected:
|
|
869
|
+
rejected: refusedLate.flatMap((g) => g.keys),
|
|
870
|
+
groups: refusedLate.map((g) => g.group),
|
|
759
871
|
note: "late-boot candidate had a refused group — the LKG/ETag stay on the last FULLY applied generation; the refresh cadence re-judges the same tree",
|
|
760
872
|
});
|
|
761
873
|
return;
|
|
@@ -764,27 +876,10 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
764
876
|
latestEffective = r.effective;
|
|
765
877
|
ccEtag = r.etag;
|
|
766
878
|
const lkgPersistedLate = await persistLkgDurable(r.effective, r.etag);
|
|
767
|
-
const reasons = restartReasons(undefined, r.effective, restartCtx());
|
|
768
|
-
if (
|
|
769
|
-
const miLate = reasons.indexOf("models-tiers");
|
|
770
|
-
if (miLate >= 0)
|
|
771
|
-
reasons.splice(miLate, 1);
|
|
772
|
-
}
|
|
773
|
-
if (planeDeferredLate) {
|
|
774
|
-
if (lkgPersistedLate) {
|
|
775
|
-
if (!reasons.includes("models-tiers"))
|
|
776
|
-
reasons.push("models-tiers");
|
|
777
|
-
planeDeferredNoHandoff = undefined;
|
|
778
|
-
}
|
|
779
|
-
else {
|
|
780
|
-
const blocked = reasons.splice(0, reasons.length);
|
|
781
|
-
planeDeferredNoHandoff = { version: r.effective.version, since: planeDeferredNoHandoff?.since ?? Date.now(), ...(blocked.length > 0 ? { blocked } : {}), planeDeferred: true, candidate: r.effective, ...(r.etag !== undefined ? { candidateEtag: r.etag } : {}) };
|
|
782
|
-
logger.warn("models_tiers_deferred_no_handoff", { version: r.effective.version, blockedReasons: blocked, note: "late-boot plane deferred but no NEXT-BOOT handoff (see CONFIG_LKG_DURABLE) — the WHOLE restart signal is withheld (it would loop); old generation keeps serving" });
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
else if (planeDeferredLate === false && lkgSurvivesRestart && !lkgPersistedLate) {
|
|
879
|
+
const reasons = restartReasons(undefined, r.effective, restartCtx(consolidationSeat?.read()));
|
|
880
|
+
if (lkgSurvivesRestart && !lkgPersistedLate) {
|
|
786
881
|
const blocked = reasons.splice(0, reasons.length);
|
|
787
|
-
planeDeferredNoHandoff = { version: r.effective.version, since:
|
|
882
|
+
planeDeferredNoHandoff = { version: r.effective.version, since: Date.now(), blocked, candidate: r.effective, ...(r.etag !== undefined ? { candidateEtag: r.etag } : {}) };
|
|
788
883
|
logger.warn("restart_candidate_publication_incomplete", { version: r.effective.version, blockedReasons: blocked, note: "late-boot candidate publication incomplete on a durable-declared deployment — restart signal withheld; retried every tick" });
|
|
789
884
|
}
|
|
790
885
|
if (reasons.length > 0)
|
|
@@ -793,7 +888,15 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
793
888
|
};
|
|
794
889
|
if (bootConfigPending) {
|
|
795
890
|
const arrivalGen = reserveArrivalGeneration();
|
|
796
|
-
|
|
891
|
+
const continueArrival = (r) => void (lkgBooted ? runTick({ result: r, ordinal: arrivalGen }) : deferredBootApply(r, arrivalGen));
|
|
892
|
+
void bootConfigPending.then((r) => {
|
|
893
|
+
if (r !== null && configProvider.kind === "remote" && candidateIdentityOf(r.effective) !== currentIdentity()) {
|
|
894
|
+
logger.warn("config_boot_arrival_identity_changed", { note: "the late boot pull landed under a center credential that is no longer current — not adopted; re-pulling once under the current credential" });
|
|
895
|
+
void pullEffective(configProvider, undefined).then(continueArrival, (err) => logger.warn("config_boot_arrival_repull_failed", { err: String(err), note: "the refresh cadence retries under the current credential" }));
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
continueArrival(r);
|
|
899
|
+
}, () => { });
|
|
797
900
|
}
|
|
798
901
|
}
|
|
799
902
|
},
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { NodeLspManager } from "@sema-agent/core";
|
|
2
1
|
import { TaskEnvRegistry } from "../capabilities/sandbox-file-send.js";
|
|
3
2
|
import { SessionEnvironmentSelection } from "../capabilities/select-environment-tool.js";
|
|
4
3
|
import type { ServiceConfig } from "../config.js";
|
|
@@ -67,6 +66,6 @@ export declare function createExecutionEnv(ctx: ExecutionEnvCtx): {
|
|
|
67
66
|
executionEnvFactory: import("@sema-agent/core").ExecutionEnvFactory | undefined;
|
|
68
67
|
worktreeReap: (() => Promise<void>) | undefined;
|
|
69
68
|
sendUserFileTaskEnvs: TaskEnvRegistry | undefined;
|
|
70
|
-
lspManager: import("../lsp/manager.js").E2bLspManager |
|
|
69
|
+
lspManager: import("@sema-agent/core").NodeLspManager | import("../lsp/manager.js").E2bLspManager | undefined;
|
|
71
70
|
};
|
|
72
71
|
//# sourceMappingURL=execution-env.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { createHostLspManager } from "../host-lsp-manager.js";
|
|
4
4
|
import { sandboxSendLaneEnabled, TaskEnvRegistry } from "../capabilities/sandbox-file-send.js";
|
|
5
5
|
import { SessionEnvironmentSelection } from "../capabilities/select-environment-tool.js";
|
|
6
6
|
import { createE2bLspManager } from "../lsp/e2b-manager.js";
|
|
@@ -290,7 +290,7 @@ export function createExecutionEnv(ctx) {
|
|
|
290
290
|
})
|
|
291
291
|
:
|
|
292
292
|
lspProvider === "host" && config.lspHostEnabled && config.requirePrincipal !== true
|
|
293
|
-
?
|
|
293
|
+
? createHostLspManager((event, fields) => logger.info(event, fields))
|
|
294
294
|
: undefined;
|
|
295
295
|
if (lspManager)
|
|
296
296
|
logger.info("lsp_enabled", { provider: lspProvider });
|