@sema-agent/server 7.100.0 → 7.101.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 +22 -1
- package/README.md +12 -1
- package/README.zh-CN.md +9 -1
- package/USAGE.md +80 -9
- package/dist/approval-card.d.ts +24 -12
- package/dist/approval-card.js +4 -3
- package/dist/approval-policy-settlement.d.ts +31 -0
- package/dist/approval-policy-settlement.js +16 -0
- package/dist/approval-reconciler.d.ts +8 -1
- package/dist/approval-reconciler.js +5 -4
- package/dist/boot/config-center.js +86 -20
- package/dist/boot/execution-env.js +20 -2
- package/dist/boot/parked-revive-gate.js +1 -0
- package/dist/boot/reapers.js +1 -0
- package/dist/boot/resolve-spec.js +25 -8
- package/dist/boot/runner-deps.js +9 -3
- package/dist/boot/stage-02-registry-pull.js +9 -0
- package/dist/boot/stores.js +4 -0
- package/dist/config-catalog.js +5 -3
- package/dist/config-center/apply-effective.d.ts +25 -0
- package/dist/config-center/apply-effective.js +144 -69
- package/dist/config-center/apply-ledger.d.ts +12 -2
- package/dist/config-center/apply-ledger.js +4 -1
- package/dist/config-center/facade.d.ts +1 -1
- package/dist/config-center/facade.js +1 -1
- package/dist/config-center/http-client.d.ts +4 -1
- package/dist/config-center/http-client.js +15 -10
- package/dist/config-center/read-warnings.d.ts +115 -6
- package/dist/config-center/read-warnings.js +115 -5
- package/dist/config-center/types.d.ts +6 -0
- package/dist/config-invariants.d.ts +2 -2
- package/dist/config-invariants.js +15 -0
- package/dist/config-provider.d.ts +4 -0
- package/dist/config-provider.js +64 -9
- package/dist/config-types.d.ts +37 -8
- package/dist/config.js +87 -22
- package/dist/deployment-governance.d.ts +45 -12
- package/dist/deployment-governance.js +37 -9
- package/dist/env-name-allowlist-knobs.d.ts +37 -0
- package/dist/env-name-allowlist-knobs.js +24 -0
- package/dist/fleet-client.d.ts +2 -1
- package/dist/hooks/hook-llm.js +13 -4
- package/dist/host-lsp-manager.d.ts +14 -2
- package/dist/host-lsp-manager.js +7 -6
- package/dist/http/admission.js +22 -7
- package/dist/http/memory-store-refusal-reply.d.ts +24 -0
- package/dist/http/memory-store-refusal-reply.js +10 -0
- package/dist/http/routes/approvals-assistant.js +1 -0
- package/dist/http/routes/capabilities.js +3 -3
- package/dist/http/routes/memory-bundle.js +3 -0
- package/dist/http/routes/memory-compliance.js +3 -5
- package/dist/http/routes/memory-origin.js +3 -5
- package/dist/http/routes/sessions.js +7 -6
- package/dist/http/routes/side-query.js +10 -4
- package/dist/instruction-source-notice.d.ts +97 -0
- package/dist/instruction-source-notice.js +78 -0
- package/dist/memory-layer-legacy-lock.d.ts +14 -0
- package/dist/memory-layer-legacy-lock.js +74 -0
- package/dist/memory-operator-faces.js +1 -17
- package/dist/memory-store-refusal.d.ts +37 -0
- package/dist/memory-store-refusal.js +14 -0
- package/dist/model-entry-refusal.d.ts +130 -0
- package/dist/model-entry-refusal.js +157 -0
- package/dist/model-provider.d.ts +9 -3
- package/dist/model-route-endpoint.d.ts +1 -1
- package/dist/model-select.d.ts +49 -4
- package/dist/model-select.js +48 -17
- package/dist/observability/fail-open.d.ts +9 -1
- package/dist/observability/fail-open.js +9 -1
- package/dist/observability/metrics.js +1 -0
- package/dist/observability/secret-env-scrub.d.ts +27 -4
- package/dist/observability/secret-env-scrub.js +22 -7
- package/dist/plugins/caching-session-store.d.ts +6 -0
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/local-session-store.d.ts +20 -25
- package/dist/plugins/local-session-store.js +111 -64
- package/dist/plugins/pg-session-storage.d.ts +7 -0
- package/dist/plugins/pg-session-storage.js +19 -0
- package/dist/plugins/remote-env-host.d.ts +3 -1
- package/dist/plugins/remote-env-host.js +3 -6
- package/dist/plugins/tidb-pool.js +5 -0
- package/dist/plugins/tidb-session-store.d.ts +13 -0
- package/dist/plugins/tidb-session-store.js +14 -0
- package/dist/plugins/web-search.d.ts +2 -1
- package/dist/plugins/web-search.js +43 -24
- package/dist/project-memory.d.ts +10 -0
- package/dist/project-memory.js +28 -14
- package/dist/run-local.d.ts +17 -15
- package/dist/run-local.js +115 -15
- package/dist/sealed-key.d.ts +5 -2
- package/dist/server-secret-env.d.ts +23 -1
- package/dist/server-secret-env.js +9 -0
- package/dist/tool-approval.d.ts +65 -31
- package/dist/tool-approval.js +96 -49
- package/dist/trace/core-keyset-guard.d.ts +27 -5
- package/dist/trace/engine-notice-wire.d.ts +27 -1
- package/dist/trace/engine-notice-wire.js +8 -0
- package/dist/trace/wire-projection-faces.d.ts +2 -2
- package/dist/trace/wire-projection-faces.js +2 -2
- package/package.json +2 -2
- package/dist/memory-layer-preflight.d.ts +0 -46
- package/dist/memory-layer-preflight.js +0 -121
|
@@ -18,10 +18,18 @@ import { createConfigProvider, raceBootFetch, BOOT_FETCH_DEFERRED } from "../con
|
|
|
18
18
|
import { executionLaneCaps, executionLaneOf } from "../execution-lane-caps.js";
|
|
19
19
|
import { createKeyResolver } from "../key-resolver.js";
|
|
20
20
|
import { ensureSealedKeyStore, reportExecutionPublicKey } from "../sealed-key.js";
|
|
21
|
-
import { applyEffective, applyCenterReadFace, mutateInPlace, logEffectiveDiff, applyCenterSkills, resolveMcpServers, resolveA2aPeers, restartReasons, modelPlaneChanged, fetchPromptArtifact } from "../config-center/facade.js";
|
|
21
|
+
import { applyEffective, applyCenterReadFace, mutateInPlace, logEffectiveDiff, applyCenterSkills, resolveMcpServers, resolveA2aPeers, restartReasons, modelPlaneChanged, withModelPlaneOf, buildEnvOnlyModelPlane, fetchPromptArtifact } from "../config-center/facade.js";
|
|
22
22
|
import { createMcpRevocationLedger, enabledMcpEntries } from "../config-center/mcp-revocation.js";
|
|
23
23
|
import { SHA256_HEX_RE } from "../digest-form.js";
|
|
24
|
-
import { createConfigApplyLedger, refusedGroups } from "../config-center/apply-ledger.js";
|
|
24
|
+
import { createConfigApplyLedger, modelPlaneCommitted, refusedGroups } from "../config-center/apply-ledger.js";
|
|
25
|
+
function lkgReadNote(scope) {
|
|
26
|
+
switch (scope) {
|
|
27
|
+
case "whole":
|
|
28
|
+
return "booting from the persisted last-known-good (all restart-to-apply faces included) — the live pull continues in the background and reconciles on arrival";
|
|
29
|
+
case "model-plane":
|
|
30
|
+
return "the live candidate's model plane was refused at boot — the persisted last-known-good supplies the model plane only (catalog and the collab templates that reference it); every other group and every restart-to-apply face stays the live candidate's";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
25
33
|
export async function createConfigCenterRuntime(ctx) {
|
|
26
34
|
const { config, logger, metrics, localRoot } = ctx;
|
|
27
35
|
let ccEtag;
|
|
@@ -114,6 +122,18 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
114
122
|
: undefined;
|
|
115
123
|
const rosterGateArmed = isRosterGateArmed(cc);
|
|
116
124
|
const modelReadyState = { ready: !rosterGateArmed };
|
|
125
|
+
const warnDroppedEntries = (r, phase) => {
|
|
126
|
+
for (const d of r.droppedEntries ?? []) {
|
|
127
|
+
logger.warn("config_entry_dropped", {
|
|
128
|
+
domain: d.domain,
|
|
129
|
+
entry: d.entry,
|
|
130
|
+
error: d.error,
|
|
131
|
+
version: r.effective.version,
|
|
132
|
+
phase,
|
|
133
|
+
note: "this one entry failed its domain schema and was dropped on its own — the rest of the candidate applies (per-entry tolerance); fix the named entry to bring it back",
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
};
|
|
117
137
|
const markRosterLanded = (eff) => {
|
|
118
138
|
if (!modelReadyState.ready && (eff.models?.models ?? []).some((m) => m.enabled !== false)) {
|
|
119
139
|
modelReadyState.ready = true;
|
|
@@ -312,7 +332,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
312
332
|
};
|
|
313
333
|
if (configProvider) {
|
|
314
334
|
const dryRun = cc?.dryRun ?? false;
|
|
315
|
-
const bootFromLkg = async (why) => {
|
|
335
|
+
const bootFromLkg = async (why, scope) => {
|
|
316
336
|
if (!lkgEnabled || dryRun)
|
|
317
337
|
return null;
|
|
318
338
|
const identity = currentIdentity();
|
|
@@ -344,7 +364,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
344
364
|
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
365
|
return null;
|
|
346
366
|
}
|
|
347
|
-
logger.info("config_loaded_lkg", { path: lkgPath, savedAt: read.lkg.savedAt, why, note:
|
|
367
|
+
logger.info("config_loaded_lkg", { path: lkgPath, savedAt: read.lkg.savedAt, why, scope, note: lkgReadNote(scope) });
|
|
348
368
|
const lkgEffective = read.lkg.effective;
|
|
349
369
|
candidateIdentity.set(lkgEffective, identity);
|
|
350
370
|
bindValidator(read.lkg.etag, identity);
|
|
@@ -353,18 +373,31 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
353
373
|
const bootApplyLkgInline = async (lkgR) => {
|
|
354
374
|
const lkgGen = generationOf(lkgR.effective.version);
|
|
355
375
|
applyLedger.seenTarget(lkgGen, lkgR.effective.version);
|
|
356
|
-
|
|
376
|
+
let lkgReport;
|
|
377
|
+
applyEffective(config, lkgR.effective, logger, {
|
|
378
|
+
leg: "boot",
|
|
379
|
+
sealedKeys,
|
|
380
|
+
generation: lkgGen,
|
|
381
|
+
report: (rep) => {
|
|
382
|
+
lkgReport = rep;
|
|
383
|
+
applyLedger.recordApply(rep);
|
|
384
|
+
},
|
|
385
|
+
});
|
|
357
386
|
applyLedger.applied(lkgGen, lkgR.effective.version);
|
|
358
387
|
await adoptCenterPrompts(lkgR.effective, "boot-lkg");
|
|
359
|
-
|
|
388
|
+
const lkgPlane = modelPlaneCommitted(lkgReport);
|
|
389
|
+
if (lkgPlane)
|
|
390
|
+
markRosterLanded(lkgR.effective);
|
|
360
391
|
effective = lkgR.effective;
|
|
361
|
-
|
|
392
|
+
if (lkgPlane)
|
|
393
|
+
appliedPlaneEff = lkgR.effective;
|
|
362
394
|
latestEffective = lkgR.effective;
|
|
363
395
|
if (lkgR.etag !== undefined)
|
|
364
396
|
ccEtag = lkgR.etag;
|
|
365
397
|
const cfgModels = (lkgR.effective.models?.models ?? []).filter((m) => m.enabled !== false).length;
|
|
366
398
|
logger.info("config_loaded", { source: "lkg", version: lkgR.effective.version, worker: cc?.worker ?? "(global)", models: cfgModels });
|
|
367
399
|
};
|
|
400
|
+
let bootApplyPhase = false;
|
|
368
401
|
try {
|
|
369
402
|
const bootFetch = pullEffective(configProvider, undefined);
|
|
370
403
|
const raced = await raceBootFetch(bootFetch, config.configBootFetchBudgetMs);
|
|
@@ -372,7 +405,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
372
405
|
if (raced === BOOT_FETCH_DEFERRED) {
|
|
373
406
|
bootConfigPending = bootFetch;
|
|
374
407
|
bootFetch.catch(() => { });
|
|
375
|
-
lkgFallback = await bootFromLkg("boot fetch deferred (budget exceeded)");
|
|
408
|
+
lkgFallback = await bootFromLkg("boot fetch deferred (budget exceeded)", "whole");
|
|
376
409
|
lkgBooted = lkgFallback !== null;
|
|
377
410
|
logger.warn("config_boot_fetch_deferred", {
|
|
378
411
|
source: configProvider.kind,
|
|
@@ -394,11 +427,13 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
394
427
|
}
|
|
395
428
|
const r = raced === BOOT_FETCH_DEFERRED ? null : raced;
|
|
396
429
|
if (r) {
|
|
430
|
+
bootApplyPhase = true;
|
|
397
431
|
const bootPromptsRaw = r.effective.prompts;
|
|
398
432
|
const bootPromptsOk = bootPromptsRaw === undefined || validatePromptsDomain(bootPromptsRaw).ok;
|
|
399
433
|
let bootClean = (r.domainErrors ?? []).length === 0 && bootPromptsOk;
|
|
400
434
|
for (const de of r.domainErrors ?? [])
|
|
401
435
|
logger.warn("config_domain_invalid", { domain: de.domain, error: de.error, note: "tolerated at BOOT (corrupt file → schema defaults; dangling ref → reported as-is); the refresh path rejects such a candidate whole and keeps the LKG (§9.5-5)" });
|
|
436
|
+
warnDroppedEntries(r, "boot");
|
|
402
437
|
if (dryRun) {
|
|
403
438
|
logEffectiveDiff(config, r.effective, logger);
|
|
404
439
|
if (bootClean)
|
|
@@ -423,9 +458,23 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
423
458
|
if (bootClean)
|
|
424
459
|
ccEtag = r.etag;
|
|
425
460
|
await adoptCenterPrompts(r.effective, "boot");
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
461
|
+
let bootPlaneEff = modelPlaneCommitted(bootReport) ? r.effective : undefined;
|
|
462
|
+
if (bootPlaneEff === undefined) {
|
|
463
|
+
const lkgPlane = await bootFromLkg("boot candidate's model plane was refused", "model-plane");
|
|
464
|
+
if (lkgPlane) {
|
|
465
|
+
let planeReport;
|
|
466
|
+
applyEffective(config, withModelPlaneOf(r.effective, lkgPlane.effective), logger, { leg: "boot", sealedKeys, generation: bootGen, report: (rep) => (planeReport = rep) });
|
|
467
|
+
if (modelPlaneCommitted(planeReport)) {
|
|
468
|
+
bootPlaneEff = lkgPlane.effective;
|
|
469
|
+
logger.warn("config_model_plane_from_lkg", { version: r.effective.version, lkgVersion: lkgPlane.effective.version, note: "the live candidate's model plane was refused at boot — serving the LKG's model plane (catalog and the collab templates that reference it) with the live candidate's other groups; the refresh cadence re-judges the candidate" });
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
if (bootPlaneEff !== undefined)
|
|
474
|
+
markRosterLanded(bootPlaneEff);
|
|
475
|
+
effective = bootPlaneEff === r.effective ? r.effective : withModelPlaneOf(r.effective, bootPlaneEff ?? buildEnvOnlyModelPlane());
|
|
476
|
+
if (bootPlaneEff !== undefined)
|
|
477
|
+
appliedPlaneEff = bootPlaneEff;
|
|
429
478
|
if (bootClean)
|
|
430
479
|
latestEffective = r.effective;
|
|
431
480
|
if (bootClean && !lkgBooted)
|
|
@@ -435,23 +484,30 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
435
484
|
logger.info("config_loaded", { source: configProvider.kind, version: r.effective.version, worker: cc?.worker ?? "(global)", models: cfgModels, ...cfgDir });
|
|
436
485
|
if (configProvider.kind === "local" && cfgModels === 0) {
|
|
437
486
|
const modelsDomainErr = (r.domainErrors ?? []).find((de) => de.domain === "models");
|
|
487
|
+
const modelsDropped = (r.droppedEntries ?? []).filter((d) => d.domain === "models");
|
|
438
488
|
const totalModels = (r.effective.models?.models ?? []).length;
|
|
439
489
|
logger.warn("config_local_no_models", {
|
|
440
490
|
...cfgDir,
|
|
441
491
|
...(modelsDomainErr ? { domainError: modelsDomainErr.error } : {}),
|
|
492
|
+
...(modelsDropped.length > 0 ? { droppedEntries: modelsDropped.map((d) => d.entry) } : {}),
|
|
442
493
|
hint: modelsDomainErr
|
|
443
494
|
? "config.d/models.json 在场但 models 域判形失败落 default(真因见本行 domainError)— 模型继续走 env 兜底"
|
|
444
|
-
:
|
|
445
|
-
?
|
|
446
|
-
:
|
|
495
|
+
: modelsDropped.length > 0 && totalModels === 0
|
|
496
|
+
? "config.d/models.json 的条目全部被逐条丢弃(逐条真因见 config_entry_dropped)— 模型继续走 env 兜底"
|
|
497
|
+
: totalModels > 0
|
|
498
|
+
? `config.d/models.json 有 ${totalModels} 条模型但全部 enabled:false — 模型继续走 env 兜底`
|
|
499
|
+
: "config.d/models.json 空或 CONFIG_LOCAL_DIR 指错目录(选目录旋钮是 CONFIG_LOCAL_DIR,不是 LOCAL_DATA_ROOT)— 模型继续走 env 兜底",
|
|
447
500
|
});
|
|
448
501
|
}
|
|
449
502
|
}
|
|
450
503
|
}
|
|
451
504
|
}
|
|
452
505
|
catch (err) {
|
|
453
|
-
|
|
454
|
-
|
|
506
|
+
if (bootApplyPhase)
|
|
507
|
+
logger.warn("config_apply_refused", { source: configProvider.kind, err: String(err), note: "the pulled candidate failed to apply at boot — falling back to the LKG / env; this is not a reachability failure" });
|
|
508
|
+
else
|
|
509
|
+
logger.warn("config_source_unreachable_using_env", { source: configProvider.kind, err: String(err) });
|
|
510
|
+
const lkgFallback = await bootFromLkg(`${bootApplyPhase ? "boot apply refused" : "boot fetch failed"}: ${String(err).slice(0, 120)}`, "whole");
|
|
455
511
|
if (lkgFallback) {
|
|
456
512
|
lkgBooted = true;
|
|
457
513
|
try {
|
|
@@ -696,6 +752,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
696
752
|
...(r.domainErrors ?? []).map((de) => ({ domain: de.domain, error: de.error })),
|
|
697
753
|
...(promptsGate.ok ? [] : [{ domain: "prompts", error: promptsGate.error }]),
|
|
698
754
|
],
|
|
755
|
+
...(r.droppedEntries !== undefined ? { droppedEntries: r.droppedEntries } : {}),
|
|
699
756
|
lkgVersion: latestEffective?.version ?? "(env)",
|
|
700
757
|
note: "candidate rejected whole (§9.5-5) — live config keeps the last-known-good; fix the named files to unblock",
|
|
701
758
|
});
|
|
@@ -703,6 +760,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
703
760
|
return "ok";
|
|
704
761
|
}
|
|
705
762
|
lastRejectedCandidate = undefined;
|
|
763
|
+
warnDroppedEntries(r, "refresh");
|
|
706
764
|
if (ccRef?.dryRun) {
|
|
707
765
|
logEffectiveDiff(config, r.effective, logger);
|
|
708
766
|
ccEtag = r.etag;
|
|
@@ -730,10 +788,13 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
730
788
|
mcpRevocations.applyEnabledEntries(enabledMcpEntries(r.effective.mcp));
|
|
731
789
|
applyLiveReadFace(r.effective, swapRunnerDeps, "refresh");
|
|
732
790
|
applyLedger.applied(tickGen, r.effective.version);
|
|
733
|
-
|
|
791
|
+
const tickPlane = modelPlaneCommitted(applyReport);
|
|
792
|
+
if (tickPlane)
|
|
793
|
+
appliedPlaneEff = r.effective;
|
|
734
794
|
planeDeferredNoHandoff = undefined;
|
|
735
795
|
await adoptCenterPrompts(r.effective, "refresh");
|
|
736
|
-
|
|
796
|
+
if (tickPlane)
|
|
797
|
+
markRosterLanded(r.effective);
|
|
737
798
|
const fullyApplied = applyReport?.fullyApplied !== false;
|
|
738
799
|
if (!fullyApplied) {
|
|
739
800
|
ccEtag = undefined;
|
|
@@ -826,10 +887,12 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
826
887
|
logger.warn("config_boot_deferred_candidate_rejected", {
|
|
827
888
|
version: r.effective.version,
|
|
828
889
|
errors: [...(r.domainErrors ?? []).map((de) => ({ domain: de.domain, error: de.error })), ...(promptsGate.ok ? [] : [{ domain: "prompts", error: promptsGate.error }])],
|
|
890
|
+
...(r.droppedEntries !== undefined ? { droppedEntries: r.droppedEntries } : {}),
|
|
829
891
|
note: "late boot pull carried an invalid candidate — env fallback keeps serving; the refresh cadence re-judges the same tree (etag not advanced)",
|
|
830
892
|
});
|
|
831
893
|
return;
|
|
832
894
|
}
|
|
895
|
+
warnDroppedEntries(r, "boot-deferred");
|
|
833
896
|
if (ccRef?.dryRun) {
|
|
834
897
|
logEffectiveDiff(config, r.effective, logger);
|
|
835
898
|
ccEtag = r.etag;
|
|
@@ -856,10 +919,13 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
856
919
|
ceilingVerdict?.judge();
|
|
857
920
|
applyLiveReadFace(r.effective, swapRunnerDeps, "boot-deferred");
|
|
858
921
|
applyLedger.applied(lateGen, r.effective.version);
|
|
859
|
-
|
|
922
|
+
const latePlane = modelPlaneCommitted(applyReportLate);
|
|
923
|
+
if (latePlane)
|
|
924
|
+
appliedPlaneEff = r.effective;
|
|
860
925
|
planeDeferredNoHandoff = undefined;
|
|
861
926
|
await adoptCenterPrompts(r.effective, "boot-deferred");
|
|
862
|
-
|
|
927
|
+
if (latePlane)
|
|
928
|
+
markRosterLanded(r.effective);
|
|
863
929
|
const fullyAppliedLate = applyReportLate?.fullyApplied !== false;
|
|
864
930
|
if (!fullyAppliedLate) {
|
|
865
931
|
ccEtag = undefined;
|
|
@@ -29,6 +29,24 @@ function boundedSessionSetter(map, maxEntries) {
|
|
|
29
29
|
map.delete(map.keys().next().value);
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
|
+
function forwardedSandboxEnvKeys(remoteExec) {
|
|
33
|
+
switch (remoteExec.provider) {
|
|
34
|
+
case "e2b":
|
|
35
|
+
return Object.keys(remoteExec.sandboxEnv ?? {}).sort();
|
|
36
|
+
case "local-docker":
|
|
37
|
+
return Object.keys(remoteExec.env ?? {}).sort();
|
|
38
|
+
case "k8s":
|
|
39
|
+
case "ssh":
|
|
40
|
+
case "adb":
|
|
41
|
+
case "host":
|
|
42
|
+
case "device":
|
|
43
|
+
return [];
|
|
44
|
+
default: {
|
|
45
|
+
const unreachable = remoteExec;
|
|
46
|
+
throw new Error(`unhandled remote-exec provider: ${String(unreachable.provider)}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
32
50
|
const MAX_CWD_SESSIONS = 4096;
|
|
33
51
|
export function createSessionScopedRegistries(maxEntries = MAX_CWD_SESSIONS) {
|
|
34
52
|
const perSessionCwd = new Map();
|
|
@@ -275,7 +293,7 @@ export function createExecutionEnv(ctx) {
|
|
|
275
293
|
config.remoteExec.provider === "local-docker";
|
|
276
294
|
const suspendable = config.remoteExec.provider === "e2b" ||
|
|
277
295
|
(config.remoteExec.provider === "k8s" && !!config.remoteExec.s3Snapshot);
|
|
278
|
-
const sandboxEnvKeys =
|
|
296
|
+
const sandboxEnvKeys = forwardedSandboxEnvKeys(config.remoteExec);
|
|
279
297
|
logger.info("remote_exec_enabled", { provider: config.remoteExec.provider, isolated, suspendable, ...(sandboxEnvKeys.length > 0 ? { sandboxEnvKeys } : {}) });
|
|
280
298
|
if (!isolated)
|
|
281
299
|
logger.warn("remote_exec_real_system", { provider: config.remoteExec.provider, note: "non-isolated target — actions are permanent; rely on the policy gate + HITL (design/61 §5)" });
|
|
@@ -290,7 +308,7 @@ export function createExecutionEnv(ctx) {
|
|
|
290
308
|
})
|
|
291
309
|
:
|
|
292
310
|
lspProvider === "host" && config.lspHostEnabled && config.requirePrincipal !== true
|
|
293
|
-
? createHostLspManager((event, fields) => logger.info(event, fields))
|
|
311
|
+
? createHostLspManager(config, (event, fields) => logger.info(event, fields))
|
|
294
312
|
: undefined;
|
|
295
313
|
if (lspManager)
|
|
296
314
|
logger.info("lsp_enabled", { provider: lspProvider });
|
|
@@ -29,6 +29,7 @@ export function createParkedReviveInheritedGate(deps) {
|
|
|
29
29
|
: { env: createHostAdjudicationEnv(config, localRoot), ...homeBase };
|
|
30
30
|
const rootSessionId = row.rootSessionId;
|
|
31
31
|
const baseline = createApprovalBaselinePolicy(config, {
|
|
32
|
+
kind: "durable",
|
|
32
33
|
question,
|
|
33
34
|
...(approvalExemptionStore && rootSessionId
|
|
34
35
|
? {
|
package/dist/boot/reapers.js
CHANGED
|
@@ -120,6 +120,7 @@ export function startReapers(ctx) {
|
|
|
120
120
|
pendingGraceMs: config.streamApproval.pendingGraceMs,
|
|
121
121
|
adhocGraceMs: config.streamApproval.adhocGraceMs,
|
|
122
122
|
orphanTtlMs: config.streamApproval.orphanTtlMs,
|
|
123
|
+
unattendedPolicy: config.unattendedApprovalPolicy,
|
|
123
124
|
...(toolApproval ? { emitRevoke: (frame, target) => void toolApproval.emitRevoke(frame, target) } : {}),
|
|
124
125
|
});
|
|
125
126
|
})();
|
|
@@ -17,7 +17,8 @@ import { composeHooks, createTaskHooks } from "../hooks/hook-runner.js";
|
|
|
17
17
|
import { HOST_POSTURE_REFUSED_CODE, taskApproverPostureHonored, taskWriteFaceRefusal } from "../hosted-posture.js";
|
|
18
18
|
import { headerStr } from "../http/principal-gate.js";
|
|
19
19
|
import { explicitOperatorOk } from "../http/server.js";
|
|
20
|
-
import { isModelAllowlisted, matchCatalogModel, modelSupportsImages, resolveTaskModel, terminalCatalogName } from "../model-select.js";
|
|
20
|
+
import { isModelAllowlisted, matchCatalogModel, modelSupportsImages, refusedCatalogEntry, resolveTaskModel, selectableCatalog, terminalCatalogName } from "../model-select.js";
|
|
21
|
+
import { modelUnavailableMessage } from "../model-entry-refusal.js";
|
|
21
22
|
import { PerTaskImageRegistry, resolveSandboxImageRef } from "../per-task-image.js";
|
|
22
23
|
import { isRemoteScratchpadLane, remoteScratchpadDirFor } from "../plugins/remote-scratchpad.js";
|
|
23
24
|
import { bindAttachmentsForTask } from "../plugins/task-attachment-store.js";
|
|
@@ -43,7 +44,10 @@ import { memoryFaceMounted } from "../memory-scope.js";
|
|
|
43
44
|
export function createResolveSpec(ctx) {
|
|
44
45
|
const { config, logger, metrics, localRoot, scenarios, principalCaps, centerRuntimeCapsResolver, getCenterPrompts, getKeyResolver, taskAttachmentStore, perSessionCwd, setSessionCwd, setSessionShellEnv, fenceSessionOwner, hookLlm, hookAgent, fleetBus, hookWakeBus, noteSessionShellGate, resumeAnchorStore, ownerAware, taskLimitCaps, taskTimeoutSec, selectEnvTool, sendUserFileToolSpec, memoryEngine, durableEnabled, approvalExemptionStore, checkpointStore, deploymentHooks, imageIndex, perTaskImage, sessionEnvSelection, liveQuestionFace, approverSeat, lockedKeys, } = ctx;
|
|
45
46
|
assertGuardPatternsUsable(config);
|
|
46
|
-
const onlySensitiveBaseline = buildOnlySensitiveBaselineWarning(config, {
|
|
47
|
+
const onlySensitiveBaseline = buildOnlySensitiveBaselineWarning(config, {
|
|
48
|
+
approvalSeat: durableEnabled ? "durable" : "absent",
|
|
49
|
+
singleUserAutoAcceptBaseline: singleUserAutoAcceptBaselineApplies(config),
|
|
50
|
+
});
|
|
47
51
|
const realTaskRootOf = (auth) => {
|
|
48
52
|
if (isSandboxPathAdjudicationLane(config.remoteExec?.provider))
|
|
49
53
|
return undefined;
|
|
@@ -217,8 +221,16 @@ export function createResolveSpec(ctx) {
|
|
|
217
221
|
if (rawAddReadDirs !== undefined && !cwdHonored(config)) {
|
|
218
222
|
logger.warn("task_additional_read_directories_ignored", { honored: false, sessionId: auth?.sessionId ?? null });
|
|
219
223
|
}
|
|
220
|
-
const wireCatalog =
|
|
221
|
-
const picked = resolveTaskModel(body.model ?? parsedSettings.settings?.model, objective, wireCatalog, config.atModelAllowlist);
|
|
224
|
+
const wireCatalog = selectableCatalog(config.models, config.tiers, config.modelRefusals);
|
|
225
|
+
const picked = resolveTaskModel(body.model ?? parsedSettings.settings?.model, objective, wireCatalog, config.atModelAllowlist, config.modelRefusals);
|
|
226
|
+
if (picked.unavailable !== undefined) {
|
|
227
|
+
const { requested, name, refusal, source } = picked.unavailable;
|
|
228
|
+
if (opts?.leg === "fresh") {
|
|
229
|
+
throw new HttpError(400, modelUnavailableMessage(source === "mention" ? "@-mention" : "model", requested.slice(0, 120), name, refusal), { code: "request.model_unavailable" });
|
|
230
|
+
}
|
|
231
|
+
metrics.inc("task_model_unavailable_fallback_total");
|
|
232
|
+
logger.warn("task_model_unavailable_fallback", { requested: requested.slice(0, 120), name, code: refusal.code, source, fallback: picked.model, sessionId: auth?.sessionId ?? null });
|
|
233
|
+
}
|
|
222
234
|
if (picked.notAllowed !== undefined) {
|
|
223
235
|
const { requested, resolved, source } = picked.notAllowed;
|
|
224
236
|
if (opts?.leg === "fresh") {
|
|
@@ -340,7 +352,11 @@ export function createResolveSpec(ctx) {
|
|
|
340
352
|
...((() => {
|
|
341
353
|
if (typeof body.compactionModel !== "string" || body.compactionModel.length === 0)
|
|
342
354
|
return {};
|
|
343
|
-
const cm = matchCatalogModel(body.compactionModel, wireCatalog);
|
|
355
|
+
const cm = matchCatalogModel(body.compactionModel, wireCatalog, config.modelRefusals);
|
|
356
|
+
const refusedCm = cm === undefined ? refusedCatalogEntry(body.compactionModel, config.modelRefusals) : undefined;
|
|
357
|
+
if (refusedCm !== undefined && opts?.leg === "fresh") {
|
|
358
|
+
throw new HttpError(400, modelUnavailableMessage("compactionModel", body.compactionModel.slice(0, 120), refusedCm.name, refusedCm.refusal), { code: "request.model_unavailable" });
|
|
359
|
+
}
|
|
344
360
|
if (cm === undefined) {
|
|
345
361
|
if (opts?.leg === "fresh") {
|
|
346
362
|
throw new HttpError(400, `unknown compactionModel "${body.compactionModel.slice(0, 120)}" — not in the configured catalog (name, tier word, or id; a catalog refresh may have removed it mid-request)`);
|
|
@@ -349,8 +365,8 @@ export function createResolveSpec(ctx) {
|
|
|
349
365
|
logger.warn("compaction_model_unknown_fallback", { requested: body.compactionModel.slice(0, 120), sessionId: auth?.sessionId ?? null });
|
|
350
366
|
return {};
|
|
351
367
|
}
|
|
352
|
-
if (!isModelAllowlisted(cm, wireCatalog, config.atModelAllowlist)) {
|
|
353
|
-
const terminal = terminalCatalogName(cm, wireCatalog) ?? cm;
|
|
368
|
+
if (!isModelAllowlisted(cm, wireCatalog, config.atModelAllowlist, config.modelRefusals)) {
|
|
369
|
+
const terminal = terminalCatalogName(cm, wireCatalog, config.modelRefusals) ?? cm;
|
|
354
370
|
if (opts?.leg === "fresh") {
|
|
355
371
|
throw new HttpError(400, `compactionModel "${body.compactionModel.slice(0, 120)}" is not in this deployment's @-mention allowlist (it resolves to catalog model "${terminal}") — the allowlist is configured by the operator (config-center models.atModelAllowlist)`, { code: "request.model_not_allowed" });
|
|
356
372
|
}
|
|
@@ -414,6 +430,7 @@ export function createResolveSpec(ctx) {
|
|
|
414
430
|
promptProvider: centerDecls ? centerPromptProvider(centerDecls, scenarioName) : cap.promptProvider,
|
|
415
431
|
toolPolicy: toolPolicyForHands(hands, durableEnabled
|
|
416
432
|
? createApprovalBaselinePolicy(config, {
|
|
433
|
+
kind: "durable",
|
|
417
434
|
question: liveQuestionFace,
|
|
418
435
|
...(approvalExemptionStore && auth?.sessionId
|
|
419
436
|
? {
|
|
@@ -423,7 +440,7 @@ export function createResolveSpec(ctx) {
|
|
|
423
440
|
: {}),
|
|
424
441
|
})
|
|
425
442
|
: singleUserAutoAcceptBaselineApplies(config)
|
|
426
|
-
? createApprovalBaselinePolicy(config)
|
|
443
|
+
? createApprovalBaselinePolicy(config, { kind: "absent" })
|
|
427
444
|
: undefined),
|
|
428
445
|
...(durableEnabled
|
|
429
446
|
? {
|
package/dist/boot/runner-deps.js
CHANGED
|
@@ -11,9 +11,11 @@ import { resolveServedSession } from "../orchestration/workflow-completion-inbox
|
|
|
11
11
|
import { defaultEngineNoticeRouter } from "../trace/engine-notice-wire.js";
|
|
12
12
|
import { WorkflowNotifyGate } from "../orchestration/workflow-notify-journal.js";
|
|
13
13
|
import { makeLoadProjectMemory, makeProbeInstructionSources } from "../project-memory.js";
|
|
14
|
+
import { createInstructionSourceSeat } from "../instruction-source-notice.js";
|
|
14
15
|
import { workflowModelAllowlistFor } from "../task-workflow.js";
|
|
15
16
|
import { buildCrossSessionInboundLayers, crossSessionDialogExpiryOf } from "../cross-session-settings.js";
|
|
16
17
|
import { createPeerDirectory } from "../peer-directory.js";
|
|
18
|
+
import { targetOutsideStoreInIncident } from "../memory-store-refusal.js";
|
|
17
19
|
export function createRunnerDepsOnAsk(toolApproval) {
|
|
18
20
|
if (!toolApproval)
|
|
19
21
|
return undefined;
|
|
@@ -188,8 +190,10 @@ export function createRunnerDeps(ctx) {
|
|
|
188
190
|
metrics.inc("memory_harvest_total", { ok: String(report.ok), phase: info.phase, incident: report.incident?.kind ?? "none" });
|
|
189
191
|
if (report.patches)
|
|
190
192
|
metrics.inc("memory_harvest_patches_total", { phase: info.phase }, (report.patches.add ?? 0) + (report.patches.update ?? 0));
|
|
191
|
-
if (report.incident)
|
|
192
|
-
|
|
193
|
+
if (report.incident) {
|
|
194
|
+
const code = targetOutsideStoreInIncident(report.incident);
|
|
195
|
+
logger.warn("memory_harvest_incident", { kind: report.incident.kind, phase: info.phase, ...(code !== undefined ? { code } : {}) });
|
|
196
|
+
}
|
|
193
197
|
const byCode = new Map();
|
|
194
198
|
for (const r of [...(report.rejections ?? []), ...(report.inboundFindings ?? [])])
|
|
195
199
|
byCode.set(r.code, (byCode.get(r.code) ?? 0) + 1);
|
|
@@ -209,7 +213,9 @@ export function createRunnerDeps(ctx) {
|
|
|
209
213
|
fileHistoryStore: fileHistoryStore ? fileHistoryStore : undefined,
|
|
210
214
|
permissionRuleStore: permissionRuleStore ? permissionRuleStore : undefined,
|
|
211
215
|
onBackgroundChildEvent: fleetBackgroundChildPublisher(fleetBus, (msg, fields) => logger.info(msg, fields)),
|
|
212
|
-
loadProjectMemory: config.requirePrincipal !== true && config.projectMemoryEnabled
|
|
216
|
+
loadProjectMemory: config.requirePrincipal !== true && config.projectMemoryEnabled
|
|
217
|
+
? makeLoadProjectMemory({ logger, instructionSource: createInstructionSourceSeat(sessionStore, sharedRunnerDeps.onNotice) })
|
|
218
|
+
: undefined,
|
|
213
219
|
probeInstructionSources: config.remoteExec?.provider === "host" && config.requirePrincipal !== true && config.projectMemoryEnabled
|
|
214
220
|
? makeProbeInstructionSources()
|
|
215
221
|
: undefined,
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { createUnpricedCeilingVerdict } from "./unpriced-ceiling-verdict.js";
|
|
2
2
|
import { createConfigCenterRuntime } from "./config-center.js";
|
|
3
|
+
import { defaultModelRefusal, refusedNameMintedRefusal } from "../model-entry-refusal.js";
|
|
3
4
|
export async function runStage02(ctx) {
|
|
4
5
|
const { config, localRoot, logger, metrics } = ctx;
|
|
5
6
|
const configCenter = await createConfigCenterRuntime({ config, logger, metrics, localRoot });
|
|
7
|
+
const noDefaultModel = defaultModelRefusal(config, "env");
|
|
8
|
+
if (noDefaultModel !== undefined) {
|
|
9
|
+
throw new Error(noDefaultModel);
|
|
10
|
+
}
|
|
11
|
+
const mintedRefused = refusedNameMintedRefusal(config);
|
|
12
|
+
if (mintedRefused !== undefined) {
|
|
13
|
+
throw new Error(mintedRefused);
|
|
14
|
+
}
|
|
6
15
|
await configCenter.applyLocalRemoteExec();
|
|
7
16
|
const ceilingVerdict = createUnpricedCeilingVerdict({ config, logger });
|
|
8
17
|
ceilingVerdict.judge();
|
package/dist/boot/stores.js
CHANGED
|
@@ -24,6 +24,8 @@ import { assertDeviceAuditRebindEventSchema, ensurePgDeviceSchema, ensureTiDBDev
|
|
|
24
24
|
import { mysqlDriver, pgDriver } from "../plugins/sql-driver.js";
|
|
25
25
|
import { assertCloudSnapshotBlobPosture, openStoreBackendWithFallback } from "../plugins/store-backend.js";
|
|
26
26
|
import { createMemoryEngineIncidentSink } from "../memory-incident-sink.js";
|
|
27
|
+
import { announceLockedLegacyMemoryLayers } from "../memory-layer-legacy-lock.js";
|
|
28
|
+
import { createEngineNoticeForwarder } from "./runner-deps.js";
|
|
27
29
|
import { buildMemoryRemoteLaneWarn, memoryEngineBackendFor, memoryEngineRemoteLanePosture, memoryEngineRootFor, memoryMountRootOf } from "../memory-scope.js";
|
|
28
30
|
import { assertToolResultProvenanceSchema } from "../plugins/tool-result-store-sql.js";
|
|
29
31
|
import { assertPermissionRuleApprovalSchema, assertPermissionRuleTicketSchema } from "../plugins/permission-rule-store-sql.js";
|
|
@@ -186,6 +188,8 @@ export async function openStores(ctx) {
|
|
|
186
188
|
}
|
|
187
189
|
else {
|
|
188
190
|
memoryEngine = memoryEngineBackendFor(config, undefined, createMemoryEngineIncidentSink({ logger, metrics }));
|
|
191
|
+
if (memoryEngine)
|
|
192
|
+
announceLockedLegacyMemoryLayers(memoryMountRootOf(memoryEngine.backend, memoryEngine.root), createEngineNoticeForwarder(logger));
|
|
189
193
|
if (memoryEngine && process.env.LOCAL_DATA_ROOT && !config.memoryEngineDir) {
|
|
190
194
|
logger.warn("memory_engine_dir_defaulted", {
|
|
191
195
|
root: memoryEngine.root,
|
package/dist/config-catalog.js
CHANGED
|
@@ -7,6 +7,7 @@ import { REMOTE_EXEC_PROVIDER_WORDS } from "./execution-lane-caps.js";
|
|
|
7
7
|
import { CENTER_READ_FACE_LIVE_KEYS } from "./config-center/read-face.js";
|
|
8
8
|
import { MODEL_PROVIDER_WORDS } from "./model-provider.js";
|
|
9
9
|
import { buildDisplaySafeUrl } from "./trace/redact.js";
|
|
10
|
+
import { describeAllowlistPostures } from "./env-name-allowlist-knobs.js";
|
|
10
11
|
export const CATALOG_VALUE_TYPES = ["boolean", "number", "string", "enum", "csv", "json", "path", "url", "secret", "opaque"];
|
|
11
12
|
export const CATALOG_TIMINGS = ["hot", "restart", "deploy", "inert"];
|
|
12
13
|
export const CATALOG_DANGER_AXES = ["security", "billing", "data"];
|
|
@@ -125,7 +126,7 @@ export const CONFIG_CATALOG = [
|
|
|
125
126
|
r("DOCKER_NETWORK", "orchestration", "enum", "local-docker 容器网络模式", { enumValues: ["none", "bridge", "host"], staticDefault: "bridge", danger: SEC }),
|
|
126
127
|
r("DOCKER_PATH", "orchestration", "path", "docker 二进制路径"),
|
|
127
128
|
r("DOCKER_PIDS_LIMIT", "orchestration", "number", "local-docker fork-bomb 背栓(--pids-limit;非法值回 adapter 默认 512+warn)", { danger: SEC, derivedDefaultNote: "缺席 ⇒ adapter 默认 512" }),
|
|
128
|
-
r("DOCKER_SANDBOX_ENV", "orchestration", "
|
|
129
|
+
r("DOCKER_SANDBOX_ENV", "orchestration", "secret", "local-docker 车道每条 docker exec 以 -e 注入的本进程 env 点名表(NAME,NAME;点到的键从 worker env 原样取,值不进 spec/center/日志;与 LSP_ENV_ALLOW / E2B_SANDBOX_ENV 同一只解析器与「点名放行」谓词:形错 / 点名名单型旋钮拒启且不回显值;本进程环境里没有的名按序号 warn、不转发;只在本车道被选中时求值;原文按凭据类对待:只回在场位、不进任何子进程)", { danger: SEC }),
|
|
129
130
|
r("DRAIN_GRACE_MS", "limitsHttp", "number", "SIGTERM 优雅排空窗(ms;期间新计费提交 503+Retry-After)。出厂默认是**服务器部署**的取值;壳自 spawn 的引擎会被壳注入更短的窗 ⇒ 排壳形关机预算时以本行的 effectiveValue(= 本进程实际生效值)为准,不照抄 staticDefault", { staticDefault: String(10 * 60 * 1000), configKey: "drainGraceMs", center: cLimits("drainGraceMs") }),
|
|
130
131
|
r("DURABLE_APPROVAL", "approval", "boolean", "durable suspend/resume HITL(需 SQL 店;决定 checkpointStore 与 /v1/approvals 面的存在性)", { danger: SEC, derivedDefaultNote: "posture 三态(S-178):显式词恒赢,缺席 = 单用户(REQUIRE_PRINCIPAL≠true)且有耐久店 ⇒ on / 多租户或无耐久店 ⇒ off;生效来源见 GET /v1/diagnostics/wiring 的 serverGates.durableApproval.source", configKey: "durableApproval" }),
|
|
131
132
|
r("E2B_ALLOW_NET", "orchestration", "boolean", "e2b 沙箱出网许可", { danger: SEC, derivedDefaultNote: "缺席 ⇒ 不铸键(adapter 默认允许)" }),
|
|
@@ -136,7 +137,7 @@ export const CONFIG_CATALOG = [
|
|
|
136
137
|
r("E2B_LIVENESS_MS", "orchestration", "number", "e2b 单命令静默活性上限(长静默构建请调大;后台+轮询仍是首选)", { derivedDefaultNote: "缺席 ⇒ adapter 默认 120s" }),
|
|
137
138
|
r("E2B_MOUNT_PATH", "orchestration", "path", "e2b 工作区根(resume 用当前值,改前先 drain 挂起任务)"),
|
|
138
139
|
r("E2B_ORPHAN_RECLAIM", "orchestration", "boolean", "崩溃遗留沙盒回收腿(boot 一次+周期;判据保守,拿不准恒不杀)", { staticDefault: "true", danger: BILL }),
|
|
139
|
-
r("E2B_SANDBOX_ENV", "orchestration", "
|
|
140
|
+
r("E2B_SANDBOX_ENV", "orchestration", "secret", "转发进 e2b 沙箱的本进程 env 点名表(NAME,NAME;点到的键从 worker env 原样取,值不进 spec/center/事件日志;与 LSP_ENV_ALLOW / DOCKER_SANDBOX_ENV 同一只解析器与「点名放行」谓词:形错 / 点名名单型旋钮拒启且不回显值;本进程环境里没有的名按序号 warn、不转发;只在本车道被选中时求值;原文按凭据类对待:只回在场位、不进任何子进程)", { danger: SEC }),
|
|
140
141
|
r("E2B_SANDBOX_MAX_MS", "orchestration", "number", "e2b 沙箱最长存活(ms)", { staticDefault: "3600000", danger: BILL }),
|
|
141
142
|
r("E2B_TEMPLATE", "orchestration", "string", "e2b 模板名(缺省 adapter 基础模板)"),
|
|
142
143
|
r("E2B_TIMEOUT_MS", "orchestration", "number", "e2b 单命令总超时(ms)"),
|
|
@@ -208,6 +209,7 @@ export const CONFIG_CATALOG = [
|
|
|
208
209
|
r("LOCKED_CONFIG_KEYS", "auth", "csv", "管理员锁定层声明(词表=core 闭集注册表,未知键拒启)", { danger: SEC, configKey: "lockedConfigKeys" }),
|
|
209
210
|
r("LOG_LEVEL", "observability", "string", "日志档位", { staticDefault: "info", configKey: "logLevel" }),
|
|
210
211
|
r("LSP_ENABLED", "orchestration", "boolean", "LSP 沙箱腿 opt-in(需烤好的 LSP 模板;host 腿另有 LSP_HOST_ENABLED)", { staticDefault: "false", configKey: "lspEnabled" }),
|
|
212
|
+
r("LSP_ENV_ALLOW", "orchestration", "secret", `host 腿语言服务器子进程 env 的点名放行名单(点到的键从服务 env 原样放回、部署方显式承担;没点到的照剥;与 host shell inheritEnv:[names] 同一只谓词;形错 / 点名名单型旋钮(自己或两只沙箱名单)拒启且不回显值;本进程环境里没有的名按序号 warn、不放行、不回显;多租户姿态(忽略时起服 warn 一次):${describeAllowlistPostures()};原文按凭据类对待:只回在场位、不进任何子进程,生效名单见起服披露行 allowed)`, { danger: SEC, derivedDefaultNote: "缺席 / 空串 ⇒ 空名单 = 全剥(7.100.0 行为)" }),
|
|
211
213
|
r("LSP_HOST_ENABLED", "orchestration", "boolean", "LSP host 腿开关(本机 language server,优雅降级)", { staticDefault: "true", configKey: "lspHostEnabled" }),
|
|
212
214
|
r("MANUAL_MODE_SHELL_GATE", "approval", "enum", "手动模式 shell 门收紧腿(off=no-op 非放松 —— 本键只有收紧半场;拼错拒启)", { danger: SEC, enumValues: ["always", "classify", "off"], echoWords: ["always", "classify"], resolve: (c) => c.manualModeShellGate ?? null, derivedDefaultNote: "off/未设 ⇒ 本键不贡献任何东西(归一成键缺席)⇒ 回显 null;真姿态只有 always/classify 两个" }),
|
|
213
215
|
r("MAX_PRINCIPAL_COST_USD", "limitsHttp", "number", "per-principal 窗内成本天花板(0=关)", { staticDefault: "0", danger: BILL, configKey: "maxPrincipalCostUsd", center: cLimits("maxPrincipalCostUsd") }),
|
|
@@ -453,7 +455,7 @@ export const CONFIG_CATALOG = [
|
|
|
453
455
|
r("UNREACHED_ASK_TTL_MS", "approval", "number", "零活流铸造的 ask 悬挂窗(ms;[60s,24h] 拒启带界)", { staticDefault: "3600000" }),
|
|
454
456
|
r("USAGE_WINDOWS", "orchestration", "opaque", "部署级治理窗(JSON 数组;滑动窗内跨任务 token/$ 预算,key=principal)", { danger: BILL }),
|
|
455
457
|
r("WEB_SEARCH_API_KEY", "orchestration", "secret", "web search 后端 API 凭据(brave/tavily)", { danger: [...SEC, ...BILL] }),
|
|
456
|
-
r("WEB_SEARCH_ENDPOINT", "orchestration", "url", "web search 后端 endpoint 覆写(searxng 实例地址;brave 下可指向 Brave 兼容网关的完整搜索 URL,如 Nólë;空 = 未设;不是 scheme://host 形的绝对 URL ⇒ 拒启)"),
|
|
458
|
+
r("WEB_SEARCH_ENDPOINT", "orchestration", "url", "web search 后端 endpoint 覆写(searxng 实例地址;brave 下可指向 Brave 兼容网关的完整搜索 URL,如 Nólë;空 = 未设;不是 scheme://host 形的绝对 URL、或带 userinfo(user[:password]@host —— 运行时 fetch 本就拒这一形)⇒ 拒启)"),
|
|
457
459
|
r("WEB_SEARCH_MAX_RESULTS", "orchestration", "number", "web search 单次结果数上限(非数 / < 1 ⇒ 拒启;> 20 夹到 20)", { derivedDefaultNote: "缺席/空 ⇒ backend 默认 10" }),
|
|
458
460
|
r("WEB_SEARCH_PROBE_ON_BOOT", "orchestration", "boolean", "boot 期 web search 连通性探测(只认 true/1;含糊值当没开——猜错方向是凭空出网)", { staticDefault: "false" }),
|
|
459
461
|
r("WEB_SEARCH_PROVIDER", "orchestration", "enum", "web search 工具后端(设合法词=装配 WebSearch;其它/缺席=不装配)", { enumValues: WEB_SEARCH_PROVIDERS, danger: SEC, resolve: (_c, env) => webSearchProviderFromEnv(env) ?? null }),
|
|
@@ -67,6 +67,31 @@ export type ApplyEffectiveOpts = ApplyLeg & {
|
|
|
67
67
|
}) => void;
|
|
68
68
|
};
|
|
69
69
|
export declare function applyEffective(config: ServiceConfig, eff: EffectiveConfig, logger: Logger | undefined, opts: ApplyEffectiveOpts): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* 🔴 **模型面组由哪些 effective 域组成 —— 唯一定义**(7.101.0 验修轮 V1 / codex V-1;OA 验修轮 V2 的以点改面)。
|
|
72
|
+
*
|
|
73
|
+
* collab 在组里:模板带模型引用,新模板配旧目录(或旧模板配新目录)就是一次混代发布。此前「模型面」散在三处各写一份 ——
|
|
74
|
+
* 世代账的键表只列 models 域的落点、stage 的 collab 闸按「模型面没被拒」ad hoc 门住、boot 按组回落 LKG 的合成只换
|
|
75
|
+
* `models` 域 —— 最后那份漏了 collab,于是 boot 回落时 LKG 的目录配上了被拒候选的模板(与 refresh 腿同态不同答)。
|
|
76
|
+
* 读者一律从这里派生,禁手抄:
|
|
77
|
+
* · stage:{@link stageModelPlane} 产出组内**每个**域的产物({@link ModelPlaneStages} 按本表映射),组被拒 ⇒ 一个域都没有;
|
|
78
|
+
* · 世代账:整组拒的 `keys` 与落地的 `applied` 都由 {@link MODEL_PLANE_SURFACES} 按本表派生({@link modelPlaneGroupReport});
|
|
79
|
+
* · boot 按组回落 LKG 的合成文档与 restart 基线:{@link withModelPlaneOf}(`boot/config-center.ts`)。
|
|
80
|
+
* (与 `config.ts` 的配置组视图 `MODEL_PLANE_GROUP_KEYS` 不是一回事:那是 `ServiceConfig` 的分节视图;这里是「中心热应用的
|
|
81
|
+
* 模型面这一组包含哪些 effective 域」。)
|
|
82
|
+
*/
|
|
83
|
+
export declare const MODEL_PLANE_DOMAINS: readonly ["models", "collab"];
|
|
84
|
+
export type ModelPlaneDomain = (typeof MODEL_PLANE_DOMAINS)[number];
|
|
85
|
+
/** 模型面组在 effective 上的那一切片(组内各域;`models` 必在、`collab` 可缺席 —— 与 `EffectiveConfig` 同形)。 */
|
|
86
|
+
export type ModelPlaneOf = Pick<EffectiveConfig, ModelPlaneDomain>;
|
|
87
|
+
/**
|
|
88
|
+
* `target` 换上 `source` 的**整个模型面**(组内每个域都取 `source` 的;`source` 缺席的域在结果里同样缺席,不留 `target` 的),
|
|
89
|
+
* 其余域原样是 `target` 的。boot 按组回落 LKG 的两处(回落 apply 的合成文档、restart 对照基线)都走这一只 —— 禁在调用点
|
|
90
|
+
* 手写 `{ ...x, models, collab }`(漏一个域正是 V1 的病形)。纯数据:不改两个入参。
|
|
91
|
+
*/
|
|
92
|
+
export declare function withModelPlaneOf<E extends EffectiveConfig>(target: E, source: ModelPlaneOf): E;
|
|
93
|
+
/** 「没有中心模型面」—— 组拒且无 LKG 时进程真正服务的那一代(env 表:没有目录、没有中心 collab 模板)。纯数据,每次新铸。 */
|
|
94
|
+
export declare function buildEnvOnlyModelPlane(): ModelPlaneOf;
|
|
70
95
|
/**
|
|
71
96
|
* UNIFORM presence semantics across the center gates (center `f95438a` adopted this from our sentinel flag —
|
|
72
97
|
* SERVICE-INTEGRATION「Runtime 治理/限额闸」): every gate field is center `.optional()`, so
|