@sema-agent/server 7.138.0 → 7.139.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 +276 -7
- package/README.md +7 -4
- package/README.zh-CN.md +6 -4
- package/USAGE.md +73 -29
- package/deploy/sema-up/README.md +1 -1
- package/deploy/sema-up/lib/lanes.json +3 -2
- package/dist/adoption/wire.d.ts +3 -3
- package/dist/approval-card.d.ts +20 -20
- package/dist/bench/s1/arms.d.ts +1 -1
- package/dist/bench/s1/arms.js +1 -3
- package/dist/bench/s1/run-firm.js +2 -2
- package/dist/boot/device-lane.d.ts +8 -3
- package/dist/boot/device-lane.js +7 -2
- package/dist/boot/execution-env.d.ts +4 -2
- package/dist/boot/execution-env.js +16 -24
- package/dist/boot/execution-lane.d.ts +1 -1
- package/dist/boot/governance-seams.d.ts +3 -2
- package/dist/boot/governance-seams.js +9 -11
- package/dist/boot/memory-consolidation.js +2 -2
- package/dist/boot/resolve-spec.d.ts +1 -1
- package/dist/boot/resolve-spec.js +8 -9
- package/dist/boot/retention-lane.d.ts +5 -5
- package/dist/boot/retention-lane.js +0 -6
- package/dist/boot/runner-deps.d.ts +3 -1
- package/dist/boot/runner-deps.js +2 -1
- package/dist/boot/session-faces.d.ts +0 -3
- package/dist/boot/session-faces.js +15 -8
- package/dist/boot/stage-02-web-admin-pull.js +2 -2
- package/dist/boot/stage-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.js +0 -1
- package/dist/boot/stage-09-leader.js +1 -2
- package/dist/boot/stage-10-http-server.js +2 -2
- package/dist/boot/stores.js +4 -4
- package/dist/boot/web-admin.js +2 -2
- package/dist/capabilities/mcp-probe.js +1 -1
- package/dist/capabilities/scenarios.d.ts +1 -1
- package/dist/capability-facts.d.ts +15 -7
- package/dist/capability-facts.js +8 -3
- package/dist/config-catalog.js +7 -7
- package/dist/config-invariants.d.ts +23 -3
- package/dist/config-invariants.js +42 -0
- package/dist/config-provider.d.ts +19 -24
- package/dist/config-provider.js +27 -12
- package/dist/config-types.d.ts +10 -5
- package/dist/config.d.ts +33 -0
- package/dist/config.js +44 -15
- package/dist/delegated-session-owner.d.ts +2 -2
- package/dist/deployment-shape.d.ts +1 -1
- package/dist/device-enrollment.d.ts +41 -2
- package/dist/device-enrollment.js +27 -12
- package/dist/device-store.d.ts +58 -85
- package/dist/device-store.js +19 -49
- package/dist/device-ws-hub.js +2 -1
- package/dist/env-name-allowlist-knobs.d.ts +5 -4
- package/dist/exec-cut.d.ts +60 -0
- package/dist/exec-cut.js +36 -0
- package/dist/execution-lane-caps.d.ts +19 -0
- package/dist/execution-lane-caps.js +10 -0
- package/dist/execution-placement.d.ts +259 -0
- package/dist/execution-placement.js +199 -0
- package/dist/field-conflict.d.ts +3 -2
- package/dist/field-conflict.js +1 -0
- package/dist/hosted-posture.d.ts +2 -2
- package/dist/http/admission.js +8 -19
- package/dist/http/checkpoint-ctx.d.ts +21 -12
- package/dist/http/checkpoint-ctx.js +4 -2
- package/dist/http/claimed-run.d.ts +1 -1
- package/dist/http/durable-run-leg.js +9 -5
- package/dist/http/execution-context.d.ts +218 -0
- package/dist/http/execution-context.js +330 -0
- package/dist/http/resume-legs.js +50 -20
- package/dist/http/route-ctx.d.ts +14 -8
- package/dist/http/routes/background.d.ts +29 -1
- package/dist/http/routes/background.js +29 -2
- package/dist/http/routes/devices.d.ts +13 -19
- package/dist/http/routes/devices.js +21 -26
- package/dist/http/routes/session-sync.js +110 -15
- package/dist/http/routes/sessions.d.ts +6 -0
- package/dist/http/routes/sessions.js +115 -11
- package/dist/http/routes/side-query.d.ts +12 -4
- package/dist/http/routes/side-query.js +4 -5
- package/dist/http/routes/tasks.js +37 -31
- package/dist/http/server.d.ts +35 -19
- package/dist/http/server.js +11 -0
- package/dist/http/session-inherit-env.d.ts +3 -4
- package/dist/http/session-inherit-env.js +1 -1
- package/dist/http/wire-types.d.ts +8 -12
- package/dist/index.d.ts +1 -0
- package/dist/memory-sync-client.d.ts +53 -14
- package/dist/memory-sync-client.js +196 -116
- package/dist/memory-sync.d.ts +1 -1
- package/dist/memory-sync.js +3 -2
- package/dist/observability/cost-taxonomy.d.ts +2 -2
- package/dist/observability/fail-open.d.ts +12 -0
- package/dist/observability/fail-open.js +12 -0
- package/dist/observability/run-terminal.js +0 -1
- package/dist/orchestration/workflow-notify-journal.js +4 -4
- package/dist/org-memory-admission.d.ts +4 -3
- package/dist/org-memory-admission.js +6 -6
- package/dist/parked-decide.d.ts +34 -9
- package/dist/parked-decide.js +12 -19
- package/dist/parked-revive-surface.d.ts +12 -15
- package/dist/parked-revive-surface.js +3 -6
- package/dist/peer-seat.d.ts +13 -7
- package/dist/peer-seat.js +37 -3
- package/dist/plugins/approval-ask-store-file.d.ts +7 -0
- package/dist/plugins/approval-ask-store-file.js +11 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +6 -0
- package/dist/plugins/approval-ask-store-memory.js +12 -0
- package/dist/plugins/approval-ask-store-sql.d.ts +22 -5
- package/dist/plugins/approval-ask-store-sql.js +30 -12
- package/dist/plugins/caching-session-store.d.ts +6 -2
- package/dist/plugins/caching-session-store.js +9 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +6 -5
- package/dist/plugins/checkpoint-store-sql.js +5 -7
- package/dist/plugins/device-store-sql.d.ts +25 -51
- package/dist/plugins/device-store-sql.js +49 -103
- package/dist/plugins/execution-placement-sql.d.ts +151 -0
- package/dist/plugins/execution-placement-sql.js +223 -0
- package/dist/plugins/file-history-store-sql.d.ts +7 -6
- package/dist/plugins/file-history-store-sql.js +5 -5
- package/dist/plugins/file-run-store.d.ts +6 -1
- package/dist/plugins/file-run-store.js +4 -0
- package/dist/plugins/fork-routing-session-store.d.ts +6 -0
- package/dist/plugins/fork-routing-session-store.js +16 -0
- package/dist/plugins/local-session-store.d.ts +149 -50
- package/dist/plugins/local-session-store.js +382 -107
- package/dist/plugins/memory-key-guards.d.ts +4 -0
- package/dist/plugins/memory-key-guards.js +1 -0
- package/dist/plugins/memory-run-store.d.ts +1 -1
- package/dist/plugins/one-time-migrations.d.ts +111 -3
- package/dist/plugins/one-time-migrations.js +380 -10
- package/dist/plugins/outcome-ledger-sql.d.ts +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +13 -15
- package/dist/plugins/permission-rule-store-sql.js +13 -16
- package/dist/plugins/pg-pool.d.ts +7 -3
- package/dist/plugins/pg-session-storage.d.ts +31 -20
- package/dist/plugins/pg-session-storage.js +120 -52
- package/dist/plugins/remote-env-adb.d.ts +20 -4
- package/dist/plugins/remote-env-adb.js +70 -62
- package/dist/plugins/remote-env-device.d.ts +30 -12
- package/dist/plugins/remote-env-device.js +18 -17
- package/dist/plugins/remote-env-e2b.d.ts +18 -4
- package/dist/plugins/remote-env-e2b.js +41 -42
- package/dist/plugins/remote-env-file-error.d.ts +2 -0
- package/dist/plugins/remote-env-file-error.js +1 -1
- package/dist/plugins/remote-env-host.d.ts +21 -8
- package/dist/plugins/remote-env-host.js +66 -70
- package/dist/plugins/remote-env-k8s.d.ts +11 -16
- package/dist/plugins/remote-env-k8s.js +61 -54
- package/dist/plugins/remote-env-local-docker.d.ts +29 -6
- package/dist/plugins/remote-env-local-docker.js +46 -59
- package/dist/plugins/remote-env-ssh.d.ts +16 -4
- package/dist/plugins/remote-env-ssh.js +72 -56
- package/dist/plugins/remote-shell.d.ts +100 -3
- package/dist/plugins/remote-shell.js +166 -2
- package/dist/plugins/retention-store-sql.d.ts +9 -6
- package/dist/plugins/retention-store-sql.js +7 -1
- package/dist/plugins/run-store-sql.d.ts +13 -3
- package/dist/plugins/run-store-sql.js +5 -0
- package/dist/plugins/schema-consistency.d.ts +15 -5
- package/dist/plugins/schema-consistency.js +14 -8
- package/dist/plugins/schema-drift-sentence.d.ts +27 -0
- package/dist/plugins/schema-drift-sentence.js +38 -0
- package/dist/plugins/session-fork.d.ts +54 -0
- package/dist/plugins/session-fork.js +38 -1
- package/dist/plugins/session-row-sql.d.ts +22 -0
- package/dist/plugins/session-row-sql.js +81 -0
- package/dist/plugins/session-store.d.ts +1 -1
- package/dist/plugins/store-backend.d.ts +1 -1
- package/dist/plugins/store-backend.js +19 -7
- package/dist/plugins/store-contracts.d.ts +25 -5
- package/dist/plugins/tidb-pool.d.ts +12 -7
- package/dist/plugins/tidb-pool.js +9 -3
- package/dist/plugins/tidb-session-store.d.ts +57 -26
- package/dist/plugins/tidb-session-store.js +118 -50
- package/dist/plugins/tool-result-store-sql.d.ts +3 -2
- package/dist/plugins/tool-result-store-sql.js +18 -10
- package/dist/project-memory.d.ts +9 -15
- package/dist/project-memory.js +5 -4
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +6 -7
- package/dist/request-value-closure.js +1 -3
- package/dist/run-local.d.ts +6 -0
- package/dist/run-local.js +24 -20
- package/dist/runs.d.ts +2 -1
- package/dist/runs.js +3 -1
- package/dist/security.d.ts +38 -12
- package/dist/security.js +8 -2
- package/dist/server-secret-env.d.ts +9 -5
- package/dist/session-children-retire.d.ts +27 -9
- package/dist/session-children-retire.js +9 -5
- package/dist/session-incarnation.d.ts +19 -9
- package/dist/session-incarnation.js +4 -2
- package/dist/session-row.d.ts +114 -5
- package/dist/session-row.js +55 -5
- package/dist/session-titler.d.ts +2 -2
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-cwd.d.ts +6 -1
- package/dist/task-mcp.d.ts +3 -3
- package/dist/tool-approval.d.ts +6 -0
- package/dist/tool-approval.js +8 -1
- package/dist/trace/project.d.ts +1 -0
- package/dist/trace/project.js +1 -0
- package/dist/trace/self-minted-wire.d.ts +111 -2
- package/dist/trace/self-minted-wire.js +38 -1
- package/dist/url-refusal.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.d.ts +17 -3
- package/dist/web-admin-client/apply-effective.js +20 -10
- package/dist/web-admin-client/skills-mcp.js +3 -2
- package/dist/web-admin-client/types.d.ts +6 -0
- package/package.json +3 -3
- package/wire-changes/server@7.139.0.json +348 -0
- package/dist/http/device-placement.d.ts +0 -175
- package/dist/http/device-placement.js +0 -145
|
@@ -70,7 +70,6 @@ export async function runStage06(ctx) {
|
|
|
70
70
|
const retentionLaneStore = backend?.retentionLane?.();
|
|
71
71
|
assertRetentionLaneWirable({
|
|
72
72
|
intervalSec: config.retentionSweep.intervalSec,
|
|
73
|
-
policy: config.retentionPolicy,
|
|
74
73
|
executor: retentionExecutor,
|
|
75
74
|
stores: [
|
|
76
75
|
{ name: "sessionStore", store: sessionStore },
|
|
@@ -6,9 +6,8 @@ import { createLeaderFace } from "./leader.js";
|
|
|
6
6
|
import { assertStaticWiringConsistent } from "../http/routes/diagnostics.js";
|
|
7
7
|
import { buildDisplaySafeUrl } from "../trace/redact.js";
|
|
8
8
|
export function runStage09(ctx) {
|
|
9
|
-
const { approvalExemptionStore, backend, backgroundAgentStore, brain, checkpointStore, checkpointCtxSealing, config, webAdmin, deploymentMods,
|
|
9
|
+
const { approvalExemptionStore, backend, backgroundAgentStore, brain, checkpointStore, checkpointCtxSealing, config, webAdmin, deploymentMods, dropSessionScoped, durableEnabled, executionEnvFactory, fileHistoryErasure, governanceSeams, localRoot, logger, mailboxRecipientLifecycle, mailboxStore, metrics, pricing, resumeAnchorStore, runStore, runnerDeps, sessionPolicyStore, sessionStore, streamApprovalGate, taskAttachmentStore, spaceReclaimer, taskListLane, toolResultStore, tracer, usageWindowStore, userInputLedgerStore, workflowCompletionInbox } = ctx;
|
|
10
10
|
const { ownerAware, sessionAudit, sessionWatchRegistry, purgeSession, instrumentDegenerate, planCacheProbe } = createSessionFaces({
|
|
11
|
-
deviceStore: deviceLane?.store,
|
|
12
11
|
dropSessionScoped,
|
|
13
12
|
config, logger, metrics, localRoot, backend, sessionStore, runStore, checkpointStore, toolResultStore,
|
|
14
13
|
resumeAnchorStore, approvalExemptionStore, sessionPolicyStore, taskAttachmentStore, fileHistoryErasure,
|
|
@@ -105,6 +105,7 @@ export async function runStage10(ctx) {
|
|
|
105
105
|
sessionMirrorRuling: principalCaps
|
|
106
106
|
? async (p) => (await principalCaps.executionRuling(p))?.sessionMirror
|
|
107
107
|
: undefined,
|
|
108
|
+
executionRuling: principalCaps ? (p) => principalCaps.executionRuling(p) : undefined,
|
|
108
109
|
instrumentDegenerate,
|
|
109
110
|
sideQueryAccounting,
|
|
110
111
|
parkedReviveSurface: parkedReviveSurface ? parkedReviveSurface : undefined,
|
|
@@ -118,7 +119,6 @@ export async function runStage10(ctx) {
|
|
|
118
119
|
planCacheProbe,
|
|
119
120
|
};
|
|
120
121
|
const governance = {
|
|
121
|
-
authorize,
|
|
122
122
|
webAdminJwtVerifier: webAdminJwtVerifier ? webAdminJwtVerifier : undefined,
|
|
123
123
|
rateLimiter,
|
|
124
124
|
costQuota,
|
|
@@ -214,7 +214,7 @@ export async function runStage10(ctx) {
|
|
|
214
214
|
const runnerFor = createHandsRunnerSelector({ full: runner, handsless: handslessRunner });
|
|
215
215
|
const sideQuery = createSideQueryLane({ brain, config, getKeyResolver: () => webAdmin.getKeyResolver() });
|
|
216
216
|
const scenarioGate = createScenarioGate({ config, scenarios, principalCaps, logger }, "peek");
|
|
217
|
-
const server = createHttpServer({ runner, runnerFor, sideQuery, scenarioGate, peerDesk, config, resolveSpec, stores, coordinators, seams, observability, governance, deployment, knobs });
|
|
217
|
+
const server = createHttpServer({ runner, runnerFor, sideQuery, scenarioGate, peerDesk, config, authorize, resolveSpec, stores, coordinators, seams, observability, governance, deployment, knobs });
|
|
218
218
|
bindServerLateSeats({ config, logger, server });
|
|
219
219
|
const fleetReconcile = startFleetReconciler({
|
|
220
220
|
bus: fleetBus,
|
package/dist/boot/stores.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { FileBackgroundAgentStore, FileMailboxStore, FileRosterStore, InMemoryUsageWindowStore, mailboxCrossProcessMountVerdict } from "@sema-agent/core";
|
|
3
3
|
import { createCorruptReadFailOpenSeat } from "../observability/corrupt-read-seat.js";
|
|
4
|
-
import { createMemorySyncRunner, createMemorySyncTransport } from "../memory-sync-client.js";
|
|
4
|
+
import { buildMemorySyncEnabledFields, createMemorySyncRunner, createMemorySyncTransport } from "../memory-sync-client.js";
|
|
5
5
|
import { memoryEmbedderFor } from "../plugins/memory-embedder.js";
|
|
6
6
|
import { ensurePgMemoryEmbedderMetaSchema, reconcileEmbedderFingerprint } from "../plugins/memory-embedder-fingerprint.js";
|
|
7
7
|
import { PgMemoryEngineBackend, ensurePgMemoryEngineSchema } from "../plugins/memory-engine-pg.js";
|
|
@@ -39,7 +39,6 @@ import { buildMemoryPosture } from "../memory-posture.js";
|
|
|
39
39
|
import { headReadOf } from "../session-incarnation.js";
|
|
40
40
|
import { establishSqlEnginePosture, sqlPoolsOf } from "../sql-engine-posture.js";
|
|
41
41
|
import { buildStorePosture } from "../store-posture.js";
|
|
42
|
-
import { buildDisplaySafeUrl } from "../trace/redact.js";
|
|
43
42
|
const DARK_REASON_PROSE = {
|
|
44
43
|
engine_off: () => "MEMORY_ENGINE=off",
|
|
45
44
|
multi_tenant_file_backend: () => "multi-tenant on the FILE backend (no tenant isolation; set MEMORY_ENGINE_BACKEND=pg|tidb to light up)",
|
|
@@ -364,16 +363,17 @@ export async function openStores(ctx) {
|
|
|
364
363
|
let memorySyncRunner;
|
|
365
364
|
if (config.memorySync) {
|
|
366
365
|
if (memoryEngine) {
|
|
366
|
+
const transport = createMemorySyncTransport({ url: config.memorySync.url, token: config.memorySync.token });
|
|
367
367
|
memorySyncRunner = createMemorySyncRunner({
|
|
368
368
|
backend: memoryEngine.backend,
|
|
369
369
|
scope: config.memorySync.scope,
|
|
370
370
|
memoryRoot: memoryEngine.root,
|
|
371
|
-
transport
|
|
371
|
+
transport,
|
|
372
372
|
log: logger,
|
|
373
373
|
...(config.memorySync.maxPushEntries !== undefined ? { maxPushEntries: config.memorySync.maxPushEntries } : {}),
|
|
374
374
|
...(config.memorySync.maxPullEntries !== undefined ? { maxPullEntries: config.memorySync.maxPullEntries } : {}),
|
|
375
375
|
});
|
|
376
|
-
logger.info("memory_sync_enabled",
|
|
376
|
+
logger.info("memory_sync_enabled", buildMemorySyncEnabledFields(transport.peer, config.memorySync.scope, memorySyncRunner.cursorPathFor(config.memorySync.scope)));
|
|
377
377
|
memorySyncRunner.trigger("boot");
|
|
378
378
|
}
|
|
379
379
|
else {
|
package/dist/boot/web-admin.js
CHANGED
|
@@ -17,7 +17,7 @@ import { answerStillCurrent, centerStateBin, credentialIdentityNow, judgeCenterC
|
|
|
17
17
|
import { createCenterConfigTier } from "../center-config-tier.js";
|
|
18
18
|
import { buildCenterCredentialHealthView, createCenterCredentialRenewer } from "../center-credential-renewer.js";
|
|
19
19
|
import { centerManagedConfigKeys } from "../web-admin-client/apply-effective.js";
|
|
20
|
-
import { createConfigProvider, raceBootFetch,
|
|
20
|
+
import { configSourceKind, createConfigProvider, raceBootFetch, BOOT_FETCH_DEFERRED } from "../config-provider.js";
|
|
21
21
|
import { ConfigDirUntrustedError } from "../config-dir-trust.js";
|
|
22
22
|
import { createKeyResolver } from "../key-resolver.js";
|
|
23
23
|
import { buildSealedKeyPublicFace, ensureCheckpointCtxSealing, ensureSealedKeyStore, reportExecutionPublicKey } from "../sealed-key.js";
|
|
@@ -161,7 +161,7 @@ export async function createWebAdminRuntime(ctx) {
|
|
|
161
161
|
catch (err) {
|
|
162
162
|
logger.warn("checkpoint_ctx_sealing_unavailable", { err: err instanceof Error ? err.message : String(err), dir: join(sealedKeyDir, "checkpoint-ctx-keys"), note: "suspended tasks' request credentials cannot be sealed on this host; with durable approvals on the boot refuses — make that directory (under the sealed-key custody directory: SEALED_KEY_DIR, default <data root>/sealed-key) creatable and chmod-able by the service, or repair / remove a key file there whose public and private halves do not belong together" });
|
|
163
163
|
}
|
|
164
|
-
const configProvider =
|
|
164
|
+
const configProvider = configSourceKind(config) !== undefined
|
|
165
165
|
? createConfigProvider({
|
|
166
166
|
...(config.configProvider ? { provider: config.configProvider } : {}),
|
|
167
167
|
...(cc ? { webAdmin: { baseUrl: cc.baseUrl, credential: cc.credential, worker: cc.worker, dryRun: cc.dryRun } } : {}),
|
|
@@ -178,7 +178,7 @@ export function createMcpProbeWalk(input, principal, desk, now = Date.now) {
|
|
|
178
178
|
timeoutMs: MCP_PROBE_VERDICT_TIMEOUT_MS,
|
|
179
179
|
concurrency: MCP_PROBE_CONCURRENCY,
|
|
180
180
|
signal: controller.signal,
|
|
181
|
-
peerSeat: desk.seat
|
|
181
|
+
peerSeat: desk.seat,
|
|
182
182
|
});
|
|
183
183
|
if (lease !== undefined)
|
|
184
184
|
void dials.then(() => lease.release(), () => lease.release());
|
|
@@ -85,7 +85,7 @@ export interface ScenarioContext {
|
|
|
85
85
|
/**
|
|
86
86
|
* [ref] / [ref]:**委派树根的见证**(停驻挂点的属主来源)—— 根会话 id + 调用方判断那一刻读到的根行住客(`delegated-session-owner.ts` 的 `DelegationRootWitness`)。
|
|
87
87
|
* 由**每一个**接了停驻挂点的取用方显式交出(一条读法,没有回落):请求腿 = 本请求经鉴权解析的会话与受理时那一读(`boot/resolve-spec.ts`);`/decide` 赎回面 = 行上的
|
|
88
|
-
* `rootSessionId`
|
|
88
|
+
* `rootSessionId` 与赎回腿写口放行的那一位住客(`parked-revive-surface.ts`,交不交座都交)。它**只**喂停驻挂点,不挂任何会话级设施(那是 {@link sessionId} 的事,
|
|
89
89
|
* 判据是「这只 bundle 是不是在那只会话上取用的」,与属主来源是两个独立判据)。缺席 = 没有根可交(boot 期探针、run-local、行上没有根)⇒ 律给哨兵。
|
|
90
90
|
* 挂点在停驻那一刻再读一次根行:住客不是见证的那一位(删了、同 id 被重新登记)⇒ 停驻否决 —— 不按新住客晋升或认领。
|
|
91
91
|
*/
|
|
@@ -33,12 +33,13 @@ export declare const CAPABILITY_FACT_WHY: {
|
|
|
33
33
|
readonly subagent_output_face_absent: "the background sub-agent output face is not wired";
|
|
34
34
|
readonly task_handle_faces_absent: "the background task-handle output/stop faces are not wired";
|
|
35
35
|
readonly session_head_face_absent: "the session store has no by-id head read (sessionStorage.headOf — owner, occupant and leaf of a session row in one read)";
|
|
36
|
+
readonly execution_placement_seat_absent: "the session store has no execution placement seat (sessionStorage.executionPlacement — the occupant and the execution placement cell of a root session row in one read)";
|
|
36
37
|
readonly checkpoint_store_absent: "no durable checkpoint store is wired (DURABLE_APPROVAL)";
|
|
37
38
|
readonly session_audit_absent: "no session audit view is wired (needs a durable session store)";
|
|
38
39
|
readonly session_watch_absent: "the session watch registry is not wired";
|
|
39
40
|
readonly session_lister_absent: "no session enumerator is wired (session store or run store listSessions)";
|
|
40
41
|
readonly session_fork_face_absent: "the session store has no fork face";
|
|
41
|
-
readonly session_row_faces_absent: "the session store has no session-row faces (headOf / sessionSummaryOf /
|
|
42
|
+
readonly session_row_faces_absent: "the session store has no session-row faces (headOf / sessionSummaryOf / writeSessionRowCells)";
|
|
42
43
|
readonly session_purge_absent: "no session purge coordinator is wired";
|
|
43
44
|
readonly session_policy_store_absent: "no session policy store is wired";
|
|
44
45
|
readonly store_backend_absent: "no store backend is wired (DB_BACKEND=memory, multi-tenant bare boot, or half-configured SQL)";
|
|
@@ -128,6 +129,13 @@ type HeadReadingSessionStore = WithMethods<OwnerAwareSessionStore, "headOf">;
|
|
|
128
129
|
export declare function sessionOwnership(d: Pick<Deps, "sessionStorage">): Fact<"session_head_face_absent", {
|
|
129
130
|
sessionStorage: HeadReadingSessionStore;
|
|
130
131
|
}>;
|
|
132
|
+
/**
|
|
133
|
+
* 执行放置读面在场:会话店带执行席(`executionPlacement`:一次行读 = 住客 + 执行放置格;SQL 两孪生与 local 恒带,引擎缺省的内存会话店没有)。
|
|
134
|
+
* 见证 = 那只席 —— `GET /v1/sessions/:id/execution-placement` 读它,且只读它(属主门判这一读的住客)。
|
|
135
|
+
*/
|
|
136
|
+
export declare function executionPlacementRead(d: Pick<Deps, "sessionStorage">): Fact<"execution_placement_seat_absent", {
|
|
137
|
+
seat: NonNullable<OwnerAwareSessionStore["executionPlacement"]>;
|
|
138
|
+
}>;
|
|
131
139
|
export declare function mcpReconnect(d: Pick<Deps, "runStore" | "sessionStorage">): Fact<"run_store_absent" | "session_head_face_absent", {
|
|
132
140
|
runStore: Store<"runStore">;
|
|
133
141
|
sessionStorage: HeadReadingSessionStore;
|
|
@@ -148,11 +156,11 @@ export declare function sessionList(d: Pick<Deps, "sessionStorage" | "runStore">
|
|
|
148
156
|
export declare function sessionFork(d: Pick<Deps, "sessionStorage">): Fact<"session_fork_face_absent" | "session_head_face_absent", {
|
|
149
157
|
sessionStorage: WithMethods<OwnerAwareSessionStore, "headOf" | "fork">;
|
|
150
158
|
}>;
|
|
151
|
-
/** 会话行可写位(`PATCH /v1/sessions/:id`):会话店的头读(属主 + 化身一次读 ——
|
|
159
|
+
/** 会话行可写位(`PATCH /v1/sessions/:id`):会话店的头读(属主 + 化身一次读 —— 门判属主,那一读就是写原语的行期望)∧ 行格写原语(锁内判、提交后另读应答行)。
|
|
152
160
|
* 三只 durable 店(SQL 双生 / local)都带;内存 dev 店没有行写口 ⇒ 501。
|
|
153
|
-
* 本面**没有**独立能力位(契约附录 B.2c 登记):老 worker 对这一动词答 405,本事实为假的部署答 501
|
|
161
|
+
* 本面**没有**独立能力位(契约附录 B.2c 登记):老 worker 对这一动词答 405,本事实为假的部署答 501;条件写也没有 —— 列表行上有 `rowTag` 即支持。 */
|
|
154
162
|
export declare function sessionPatch(d: Pick<Deps, "sessionStorage">): Fact<"session_row_faces_absent", {
|
|
155
|
-
sessionStorage: WithMethods<OwnerAwareSessionStore, "headOf" | "
|
|
163
|
+
sessionStorage: WithMethods<OwnerAwareSessionStore, "headOf" | "writeSessionRowCells">;
|
|
156
164
|
}>;
|
|
157
165
|
export declare function sessionDelete(d: Pick<Deps, "purgeSession" | "sessionStorage">): Fact<"session_purge_absent" | "session_head_face_absent", {
|
|
158
166
|
purge: Store<"purgeSession">;
|
|
@@ -162,11 +170,11 @@ export declare function sessionPolicy(d: Pick<Deps, "sessionPolicyStore" | "sess
|
|
|
162
170
|
policyStore: Store<"sessionPolicyStore">;
|
|
163
171
|
sessionStorage: HeadReadingSessionStore;
|
|
164
172
|
}>;
|
|
165
|
-
type SyncSessionStore = WithMethods<OwnerAwareSessionStore, "exportEntries" | "exportEntriesStream" | "beginImportStaging" | "headOf" | "sessionSummaryOf" | "
|
|
173
|
+
type SyncSessionStore = WithMethods<OwnerAwareSessionStore, "exportEntries" | "exportEntriesStream" | "beginImportStaging" | "headOf" | "sessionSummaryOf" | "writeSessionRowCells">;
|
|
166
174
|
type SessionSyncWhy = "store_backend_absent" | "file_history_store_absent" | "session_export_absent" | "session_import_staging_absent" | "session_row_faces_absent" | "policy_purge_absent";
|
|
167
175
|
/** 会话对等同步的**对话半族**(manifest / entries / plan / import 两相):后端 ∧ 文件历史店 ∧ 导出两面 ∧ staged 导入面 ∧
|
|
168
|
-
* 会话行三口(门读头 `headOf` —— 属主 + 化身一次读,属主判门、化身给 identical 短路腿;manifest 带 `title` / `pinned
|
|
169
|
-
*
|
|
176
|
+
* 会话行三口(门读头 `headOf` —— 属主 + 化身一次读,属主判门、化身给 identical 短路腿;manifest 带 `title` / `pinned`;导入经行格写原语以 `replay` 写者
|
|
177
|
+
* 按导入落定的那一位住客重放它们)∧ policy 店能清(overwrite-dst 的 commit 要擦目的端旧 policy 行)。
|
|
170
178
|
* 文件历史的 blob 搬运是另一只事实。 */
|
|
171
179
|
export declare function sessionSync(d: Pick<Deps, "backend" | "sessionStorage" | "fileHistoryStore" | "sessionPolicyStore">): Fact<SessionSyncWhy, {
|
|
172
180
|
backend: Store<"backend">;
|
package/dist/capability-facts.js
CHANGED
|
@@ -13,12 +13,13 @@ export const CAPABILITY_FACT_WHY = {
|
|
|
13
13
|
subagent_output_face_absent: "the background sub-agent output face is not wired",
|
|
14
14
|
task_handle_faces_absent: "the background task-handle output/stop faces are not wired",
|
|
15
15
|
session_head_face_absent: "the session store has no by-id head read (sessionStorage.headOf — owner, occupant and leaf of a session row in one read)",
|
|
16
|
+
execution_placement_seat_absent: "the session store has no execution placement seat (sessionStorage.executionPlacement — the occupant and the execution placement cell of a root session row in one read)",
|
|
16
17
|
checkpoint_store_absent: "no durable checkpoint store is wired (DURABLE_APPROVAL)",
|
|
17
18
|
session_audit_absent: "no session audit view is wired (needs a durable session store)",
|
|
18
19
|
session_watch_absent: "the session watch registry is not wired",
|
|
19
20
|
session_lister_absent: "no session enumerator is wired (session store or run store listSessions)",
|
|
20
21
|
session_fork_face_absent: "the session store has no fork face",
|
|
21
|
-
session_row_faces_absent: "the session store has no session-row faces (headOf / sessionSummaryOf /
|
|
22
|
+
session_row_faces_absent: "the session store has no session-row faces (headOf / sessionSummaryOf / writeSessionRowCells)",
|
|
22
23
|
session_purge_absent: "no session purge coordinator is wired",
|
|
23
24
|
session_policy_store_absent: "no session policy store is wired",
|
|
24
25
|
store_backend_absent: "no store backend is wired (DB_BACKEND=memory, multi-tenant bare boot, or half-configured SQL)",
|
|
@@ -99,6 +100,10 @@ export function sessionOwnership(d) {
|
|
|
99
100
|
const s = d.sessionStorage;
|
|
100
101
|
return headReadOf(s) !== undefined ? yes({ sessionStorage: s }) : no("session_head_face_absent");
|
|
101
102
|
}
|
|
103
|
+
export function executionPlacementRead(d) {
|
|
104
|
+
const seat = d.sessionStorage?.executionPlacement;
|
|
105
|
+
return seat !== undefined ? yes({ seat }) : no("execution_placement_seat_absent");
|
|
106
|
+
}
|
|
102
107
|
export function mcpReconnect(d) {
|
|
103
108
|
const runs = durableRuns(d);
|
|
104
109
|
if (!runs.available)
|
|
@@ -133,7 +138,7 @@ export function sessionFork(d) {
|
|
|
133
138
|
}
|
|
134
139
|
export function sessionPatch(d) {
|
|
135
140
|
const s = d.sessionStorage;
|
|
136
|
-
if (headReadOf(s) === undefined || s?.
|
|
141
|
+
if (headReadOf(s) === undefined || s?.writeSessionRowCells === undefined)
|
|
137
142
|
return no("session_row_faces_absent");
|
|
138
143
|
return yes({ sessionStorage: s });
|
|
139
144
|
}
|
|
@@ -163,7 +168,7 @@ export function sessionSync(d) {
|
|
|
163
168
|
return no("session_export_absent");
|
|
164
169
|
if (s.beginImportStaging === undefined)
|
|
165
170
|
return no("session_import_staging_absent");
|
|
166
|
-
if (headReadOf(s) === undefined || s.sessionSummaryOf === undefined || s.
|
|
171
|
+
if (headReadOf(s) === undefined || s.sessionSummaryOf === undefined || s.writeSessionRowCells === undefined)
|
|
167
172
|
return no("session_row_faces_absent");
|
|
168
173
|
if (overwriteWipeIncapable(d.sessionPolicyStore))
|
|
169
174
|
return no("policy_purge_absent");
|
package/dist/config-catalog.js
CHANGED
|
@@ -109,7 +109,7 @@ export const CONFIG_CATALOG = [
|
|
|
109
109
|
r("CONFIG_LKG_PATH", "integrations", "path", "LKG 落盘路径(设了 ⇒ 派生一条读拒行 = 这条绝对路径:根锚定,只守这一个文件,经符号链接的目录时引擎沿链连目标一起守;大小写不敏感;用户仓里同尾的路径读得到;空串拒启)", { derivedDefaultNote: "缺席 ⇒ 配置根(SEMA_CONFIG_DIR,缺省 ~/.sema)下按 worker + 凭证身份分箱派生", configKey: "configLkgPath" }),
|
|
110
110
|
r("CONFIG_LOCAL_DIR", "integrations", "path", "本地配置源根(config.d/<domain>.json);兼作数据根回落链一环", { configKey: "configLocalDir", danger: DATA }),
|
|
111
111
|
r("CONFIG_LOCAL_OWNER_UID", "integrations", "number", "本地配置源读之前的目录信任判官多信的那一个属主 uid(本服务用户与 root 之外 —— userns-remap 的 bind-mount、运维用户持有的配置);只放宽属主判据,组 / 他人可写照拒;形错拒启", { configKey: "configLocalOwnerUid", danger: SEC, derivedDefaultNote: "缺席 = config.d 路径上的目录与文档只许属于本服务用户或 root" }),
|
|
112
|
-
r("CONFIG_PROVIDER", "integrations", "enum",
|
|
112
|
+
r("CONFIG_PROVIDER", "integrations", "enum", `配置源双模选择(闭集,逐字比较;认不出的词 ⇒ 拒启;remote 而 ${WEB_ADMIN_ENV.url} 缺席 ⇒ 拒启 —— remote 的配置只来自那只中心)`, { enumValues: CONFIG_PROVIDER_WORDS, derivedDefaultNote: `缺席:${WEB_ADMIN_ENV.url} 在场 ⇒ remote,否则纯 env(无管道)`, configKey: "configProvider" }),
|
|
113
113
|
r("CONFIG_REQUIRE_ROSTER", "integrations", "boolean", "远程 registry 非 dryRun 时布防 ready 门:roster 未落地 ⇒ 计费提交 503 + /health ready:false(严格 'true')", { staticDefault: "false" }),
|
|
114
114
|
r("CORS_ORIGIN", "auth", "csv", "CORS 白名单(单值 v1 兼容回显;多值按请求 Origin 匹配 + Vary;未设=无 CORS 面)", { danger: SEC, configKey: "corsOrigins" }),
|
|
115
115
|
r("COST_QUOTA_WINDOW_SEC", "limitsHttp", "number", "per-principal 成本配额窗长(秒);SQL 腿窗长进桶主键 ⇒ center 腿显式 deferred(重启生效)", { staticDefault: "86400", danger: BILL, configKey: "costQuotaWindowSec", center: cLimits("costQuotaWindowSec", { timing: "restart", restartReason: "cost-quota-window" }) }),
|
|
@@ -139,7 +139,7 @@ export const CONFIG_CATALOG = [
|
|
|
139
139
|
r("DOCKER_NETWORK", "orchestration", "enum", "local-docker 容器网络模式", { enumValues: ["none", "bridge", "host"], staticDefault: "bridge", danger: SEC }),
|
|
140
140
|
r("DOCKER_PATH", "orchestration", "path", "docker 二进制路径"),
|
|
141
141
|
r("DOCKER_PIDS_LIMIT", "orchestration", "number", "local-docker fork-bomb 背栓(--pids-limit;非法值回 adapter 默认 512+warn)", { danger: SEC, derivedDefaultNote: "缺席 ⇒ adapter 默认 512" }),
|
|
142
|
-
r("DOCKER_SANDBOX_ENV", "orchestration", "secret", "local-docker 车道每条 docker exec 以 -e 注入的本进程 env 点名表(NAME,NAME;点到的键从 worker env 原样取,值不进 spec/center/日志;与 LSP_ENV_ALLOW / E2B_SANDBOX_ENV 同一只解析器与「点名放行」谓词:形错 /
|
|
142
|
+
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 }),
|
|
143
143
|
r("DRAIN_GRACE_MS", "limitsHttp", "number", "SIGTERM 优雅排空窗(ms;期间新计费提交 503+Retry-After)。出厂默认是**服务器部署**的取值;壳自 spawn 的引擎会被壳注入更短的窗 ⇒ 排壳形关机预算时以本行的 effectiveValue(= 本进程实际生效值)为准,不照抄 staticDefault", { staticDefault: String(10 * 60 * 1000), configKey: "drainGraceMs", center: cLimits("drainGraceMs") }),
|
|
144
144
|
r("DRAIN_SECOND_SIGNAL_MIN_GAP_MS", "limitsHttp", "number", `排空期「第二发信号 = 硬停」的最小间隔(ms;锚 = 本次排空的第一发停止信号 —— SIGTERM / SIGHUP 升级进的排空,入口那一发就是它;排空口 / 租约被拒 / 附着租约自退进的排空,到达的第一发被吸收、不缩短期限。SIGTERM / SIGINT 与锚相隔不足 ⇒ 同一拍的重复投递,一行 drain_duplicate_signal_ignored 后忽略、排空继续;0 = 关,恒按第二发硬停;须为 [${DRAIN_SECOND_SIGNAL_MIN_GAP_BOUNDS.minMs}, ${DRAIN_SECOND_SIGNAL_MIN_GAP_BOUNDS.maxMs}] 内十进制整数(上界 = DRAIN_GRACE_MS 地板),小数 / 负数 / 越界拒启)`, { staticDefault: String(DRAIN_SECOND_SIGNAL_MIN_GAP_DEFAULT_MS), configKey: "drainSecondSignalMinGapMs" }),
|
|
145
145
|
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" }),
|
|
@@ -151,7 +151,7 @@ export const CONFIG_CATALOG = [
|
|
|
151
151
|
r("E2B_LIVENESS_MS", "orchestration", "number", LIVENESS_KNOB_SEMANTICS("e2b"), { derivedDefaultNote: LIVENESS_KNOB_DEFAULT_NOTE }),
|
|
152
152
|
r("E2B_MOUNT_PATH", "orchestration", "path", "e2b 工作区根(resume 用当前值,改前先 drain 挂起任务)"),
|
|
153
153
|
r("E2B_ORPHAN_RECLAIM", "orchestration", "boolean", "崩溃遗留沙盒回收腿(boot 一次+周期;判据保守,拿不准恒不杀)", { staticDefault: "true", danger: BILL }),
|
|
154
|
-
r("E2B_SANDBOX_ENV", "orchestration", "secret", "转发进 e2b 沙箱的本进程 env 点名表(NAME,NAME;点到的键从 worker env 原样取,值不进 spec/center/事件日志;与 LSP_ENV_ALLOW / DOCKER_SANDBOX_ENV 同一只解析器与「点名放行」谓词:形错 /
|
|
154
|
+
r("E2B_SANDBOX_ENV", "orchestration", "secret", "转发进 e2b 沙箱的本进程 env 点名表(NAME,NAME;点到的键从 worker env 原样取,值不进 spec/center/事件日志;与 LSP_ENV_ALLOW / DOCKER_SANDBOX_ENV 同一只解析器与「点名放行」谓词:形错 / 点名名单型旋钮 / 点名本服务自有凭据名(会把本服务的凭据装进模型读得到的沙箱;判官 = 引擎拒白名单的同一只)拒启且不回显值;本进程环境里没有的名按序号 warn、不转发;只在本车道被选中时求值;原文按凭据类对待:只回在场位、不进任何子进程)", { danger: SEC }),
|
|
155
155
|
r("E2B_SANDBOX_MAX_MS", "orchestration", "number", "e2b 沙箱最长存活(ms)", { staticDefault: "3600000", danger: BILL }),
|
|
156
156
|
r("E2B_TEMPLATE", "orchestration", "string", "e2b 模板名(缺省 adapter 基础模板)"),
|
|
157
157
|
r("E2B_TIMEOUT_MS", "orchestration", "number", "e2b 单命令总超时(ms)"),
|
|
@@ -208,10 +208,10 @@ export const CONFIG_CATALOG = [
|
|
|
208
208
|
r("K8S_LIVENESS_MS", "orchestration", "number", LIVENESS_KNOB_SEMANTICS("k8s"), { derivedDefaultNote: LIVENESS_KNOB_DEFAULT_NOTE }),
|
|
209
209
|
r("K8S_MEMORY", "orchestration", "string", "沙箱 pod 内存限额(2Gi 默认曾被真 OOM)"),
|
|
210
210
|
r("K8S_MOUNT_PATH", "orchestration", "path", "k8s 工作区挂载路径"),
|
|
211
|
-
r("K8S_NAMESPACE", "orchestration", "string", "沙箱 pod namespace"),
|
|
211
|
+
r("K8S_NAMESPACE", "orchestration", "string", "沙箱 pod 所在的 namespace(REMOTE_EXEC=k8s 必需件,与 K8S_SANDBOX_IMAGE 同级:缺席、空串或只有空白 ⇒ 起服拒,拒句点名本旋钮;服务不带内置缺省 —— 部署的声明是唯一来源,随包 chart 已显式设为 sandbox.namespace;只在 REMOTE_EXEC=k8s 被选中时求值)"),
|
|
212
212
|
r("K8S_RUNTIME_CLASS", "orchestration", "string", "沙箱 pod runtimeClass(Kata 等)"),
|
|
213
213
|
r("K8S_SANDBOX_BROKER_IMAGE", "orchestration", "string", "成员 git 凭据代理容器的镜像(k8s 沙箱 pod 的 containers[1],只挂在成员 run 的 pod 上;建议填本引擎自身镜像 —— 代理是本包里固定路径的一只程序,命令固定);不设 ⇒ 成员 git 凭据平面关(GET /v1/capabilities 的 credentialPlane.sandboxGit = broker_image_unset),任何 pod 都不挂代理,pod 形逐字节同不设时;只在 REMOTE_EXEC=k8s 被选中时求值"),
|
|
214
|
-
r("K8S_SANDBOX_ENV", "orchestration", "secret", `转发进 k8s 沙箱 pod 容器 env 的本进程 env 点名表(NAME,NAME;点到的键从 worker env 原样取,值只进该 pod 自己的 Secret —— pod spec 的容器 env 只带 secretKeyRef 引用、不带值,Secret 随 pod 由集群回收;不进工作区 / 快照 / center / 事件日志;沙箱命名空间的 Role 要 secrets ${SANDBOX_SECRET_SEAT_VERBS.env.join(" / ")},起服问不许即拒启;与 LSP_ENV_ALLOW / E2B_SANDBOX_ENV / DOCKER_SANDBOX_ENV 同一只解析器与「点名放行」谓词:形错 /
|
|
214
|
+
r("K8S_SANDBOX_ENV", "orchestration", "secret", `转发进 k8s 沙箱 pod 容器 env 的本进程 env 点名表(NAME,NAME;点到的键从 worker env 原样取,值只进该 pod 自己的 Secret —— pod spec 的容器 env 只带 secretKeyRef 引用、不带值,Secret 随 pod 由集群回收;不进工作区 / 快照 / center / 事件日志;沙箱命名空间的 Role 要 secrets ${SANDBOX_SECRET_SEAT_VERBS.env.join(" / ")},起服问不许即拒启;与 LSP_ENV_ALLOW / E2B_SANDBOX_ENV / DOCKER_SANDBOX_ENV 同一只解析器与「点名放行」谓词:形错 / 点名名单型旋钮 / 点名本服务自有凭据名(会把本服务的凭据装进模型读得到的沙箱;判官 = 引擎拒白名单的同一只)拒启且不回显值;本进程环境里没有的名按序号 warn、不转发;与包源派生 env 撞名时显式名单胜;只在本车道被选中时求值;原文按凭据类对待:只回在场位、不进任何子进程)`, { danger: SEC }),
|
|
215
215
|
r("K8S_SANDBOX_IMAGE", "orchestration", "string", "k8s 车道沙箱镜像(REMOTE_EXEC=k8s 必需件)"),
|
|
216
216
|
r("K8S_SANDBOX_IPV6", "orchestration", "enum", "k8s 沙箱 pod 的 IPv6:disabled = pod 级 sysctl 关 IPv6(net.ipv6.conf.all / default.disable_ipv6=1;两只都不在 k8s 的 safe sysctl 表里 ⇒ 每个节点 kubelet 要 --allowed-unsafe-sysctls 点名,否则 pod 起不来;沙箱 ns 不能 enforce PodSecurity baseline / restricted);enabled = 不动 pod(pod 保留平台给的 IPv6,只执行 IPv4 的出网策略管不到它,起服自检每次一行 sandbox_egress_policy_gap{kind: ipv6_enabled});词表外拒启", { enumValues: SANDBOX_IPV6_WORDS, staticDefault: SANDBOX_IPV6_DEFAULT, danger: SEC }),
|
|
217
217
|
r("K8S_TIMEOUT_MS", "orchestration", "number", "k8s 沙箱 pod 寿命(activeDeadlineSeconds,ms;整只 pod 的泄漏护栏,后台任务超时也被它钳;各条命令的超时见工具超时)"),
|
|
@@ -409,8 +409,8 @@ export const CONFIG_CATALOG = [
|
|
|
409
409
|
r("RESOURCE_SUSPEND_TOTAL_TOKENS", "approval", "number", "跨片 token 总额(0=不设;与 MAX_TASK_TOKENS 的 per-slice 窗是两根轴)", { staticDefault: "0", danger: BILL, configKey: "resourceSuspendTotalTokens" }),
|
|
410
410
|
r("RESOURCE_SUSPEND_TTL_SEC", "approval", "number", "resource/preempt checkpoint 的弃置 GC TTL(秒;0 ⇒ core 默认 30d)", { staticDefault: "0", danger: DATA, configKey: "resourceSuspendTtlSec" }),
|
|
411
411
|
r("RETENTION_MAX_AGE_DAYS", "auth", "number", "托管留存期声明(core 启动期能力校验;真删除归 sweep lane)", { danger: DATA }),
|
|
412
|
-
r("RETENTION_MODE", "auth", "enum", "留存 sweep 灰度档(拼错拒启 —— audit-only 谎成 enforce
|
|
413
|
-
r("RETENTION_SWEEP_INTERVAL_SEC", "auth", "number", "留存 sweep 节律(秒;0=lane
|
|
412
|
+
r("RETENTION_MODE", "auth", "enum", "留存 sweep 灰度档(拼错拒启 —— audit-only 谎成 enforce 两个方向都致命;enforce 而 RETENTION_MAX_AGE_DAYS 缺、或 RETENTION_SWEEP_INTERVAL_SEC 缺 / 为 0 ⇒ 拒启)", { enumValues: ["audit-only", "enforce"], staticDefault: "audit-only", danger: DATA, resolve: (c) => c.retentionSweep.mode }),
|
|
413
|
+
r("RETENTION_SWEEP_INTERVAL_SEC", "auth", "number", "留存 sweep 节律(秒;0=lane 关;> 0 而 RETENTION_MAX_AGE_DAYS 缺 ⇒ 拒启)", { staticDefault: "0", danger: DATA }),
|
|
414
414
|
r("REWIND_SNAPSHOT_MAX_MB", "store", "number", "已退役(S-15 整树快照纪元退役):设了只 boot warn 一次,零行为", { envTiming: "inert" }),
|
|
415
415
|
r("ROSTER_RETENTION_MS", "orchestration", "number", "agent_roster 行 TTL(ms;SQL twins 扩展面)", { staticDefault: String(30 * 24 * 60 * 60 * 1000), danger: DATA, configKey: "rosterRetentionMs" }),
|
|
416
416
|
r("ROUTER_ENABLED", "orchestration", "boolean", "A 价值路由(per-task 编排自动决策;ship-dark)", { staticDefault: "false", configKey: "routerEnabled" }),
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* 依赖纪律:本文件是**叶**(只 type-import config-types + 值引 deployment-governance 的守卫集编译门),
|
|
26
26
|
* 不引 config.ts,故 config.ts / runs.ts 都可以安全引它。
|
|
27
27
|
*/
|
|
28
|
-
import type { ServiceConfigFlat } from "./config-types.js";
|
|
28
|
+
import type { ConfigProviderWord, ServiceConfigFlat } from "./config-types.js";
|
|
29
29
|
/**
|
|
30
30
|
* 活体心跳周期(ms)——`runs.ts` 的 `HEARTBEAT_MS` 就是它(那边 re-export,单源在此)。
|
|
31
31
|
*
|
|
@@ -34,9 +34,9 @@ import type { ServiceConfigFlat } from "./config-types.js";
|
|
|
34
34
|
*/
|
|
35
35
|
export declare const LIVENESS_HEARTBEAT_MS = 30000;
|
|
36
36
|
/** 闭集:新增一条不变量必须在这里加词(拼错 = 编译红,而不是运行期悄悄不判)。 */
|
|
37
|
-
export type CrossInvariantId = "run-stale-heartbeat" | "bind-posture" | "bake-runner-credential" | "direct-door-anchors" | "operator-principals-required" | "operator-single-user" | "bake-operator-principals" | "sensitive-write-patterns" | "leader-host-lane" | "multi-tenant-shared-lane" | "leader-durable-store" | "device-durable-store" | "device-durable-approval" | "model-provider-word" | "gateway-url-userinfo" | "anthropic-credential-exclusive" | "model-route-endpoint" | "default-model-resolvable" | "refused-names-not-minted" | "require-execution-lane" | "center-one-identity" | "workflow-park-decision-domain";
|
|
37
|
+
export type CrossInvariantId = "run-stale-heartbeat" | "bind-posture" | "bake-runner-credential" | "direct-door-anchors" | "operator-principals-required" | "operator-single-user" | "bake-operator-principals" | "sensitive-write-patterns" | "leader-host-lane" | "multi-tenant-shared-lane" | "leader-durable-store" | "device-durable-store" | "device-durable-approval" | "model-provider-word" | "gateway-url-userinfo" | "anthropic-credential-exclusive" | "model-route-endpoint" | "default-model-resolvable" | "refused-names-not-minted" | "require-execution-lane" | "center-one-identity" | "workflow-park-decision-domain" | "remote-config-provider-url" | "retention-lane-complete";
|
|
38
38
|
/** 表读的键集(取自平铺配置型 ⇒ 键名/类型永不与真配置漂)。 */
|
|
39
|
-
export type CrossInvariantView = Readonly<Pick<ServiceConfigFlat, "runStaleSec" | "authToken" | "authTokens" | "allowUnauthedWrites" | "imageBakes" | "directApprovalDoor" | "durableApproval" | "approvalHmacKeys" | "principalJwtPubkeys" | "principalJwtIss" | "principalJwtAud" | "requirePrincipal" | "operatorPrincipals" | "operatorSingleUser" | "sensitiveWritePatterns" | "leaderEnabled" | "selfOrchestrationEnabled" | "workflowRunStoreBackend" | "remoteExec" | "requireExecutionLane" | "dbBackend" | "tidb" | "pg" | "envModel" | "gatewayBaseUrl" | "gatewayFallbackUrls" | "anthropic" | "models" | "modelRefusals" | "tiers" | "authBridgeIssuer" | "webAdmin">>;
|
|
39
|
+
export type CrossInvariantView = Readonly<Pick<ServiceConfigFlat, "runStaleSec" | "authToken" | "authTokens" | "allowUnauthedWrites" | "imageBakes" | "directApprovalDoor" | "durableApproval" | "approvalHmacKeys" | "principalJwtPubkeys" | "principalJwtIss" | "principalJwtAud" | "requirePrincipal" | "operatorPrincipals" | "operatorSingleUser" | "sensitiveWritePatterns" | "leaderEnabled" | "selfOrchestrationEnabled" | "workflowRunStoreBackend" | "remoteExec" | "requireExecutionLane" | "dbBackend" | "tidb" | "pg" | "envModel" | "gatewayBaseUrl" | "gatewayFallbackUrls" | "anthropic" | "models" | "modelRefusals" | "tiers" | "authBridgeIssuer" | "webAdmin" | "configProvider" | "retentionPolicy" | "retentionSweep">>;
|
|
40
40
|
export interface CrossInvariantInput {
|
|
41
41
|
/** 现役配置(boot 期 = 候选自身)。 */
|
|
42
42
|
readonly live: CrossInvariantView;
|
|
@@ -107,6 +107,26 @@ export declare function workflowParkDecisionDomainRefusal(v: Pick<CrossInvariant
|
|
|
107
107
|
* 标准部署形。没有 web 基址 ⇒ 无可互证,过。
|
|
108
108
|
*/
|
|
109
109
|
export declare function centerIdentityRefusal(v: Pick<CrossInvariantView, "authBridgeIssuer" | "webAdmin">): string | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* `remote-config-provider-url` —— **配置源的词要么兑现、要么拒,从不被读成另一种源**。`CONFIG_PROVIDER=remote` 说的是「这台 worker 的配置来自中心」,
|
|
112
|
+
* 中心就是 `WEB_ADMIN_ENV.url` 那一只;没有它,这句话无处兑现 —— 不建配置源(服务端)或读本地 `config.d`(run-local)都是把它读成了另一种源,
|
|
113
|
+
* 多租部署的 entitlement / 模型目录 / 治理整份缺席而进程照起。判据与拒句的唯一属主;配置源判官(`config-provider.ts` 的 `configSourceKind`)
|
|
114
|
+
* 收到这一组合时抛的也是这一句(到得了那里 = 有人绕过了 `loadConfig`)。状态型:两只键都只来自 env、运行期无写点 ⇒ 热路径上恒与 boot 同答。
|
|
115
|
+
*/
|
|
116
|
+
export declare function remoteConfigProviderUrlRefusal(v: {
|
|
117
|
+
readonly configProvider?: ConfigProviderWord | undefined;
|
|
118
|
+
readonly webAdmin?: unknown;
|
|
119
|
+
}): string | undefined;
|
|
120
|
+
/**
|
|
121
|
+
* `retention-lane-complete` —— **被要的扫车道必须齐**。要车道的旋钮有两根:节律(`RETENTION_SWEEP_INTERVAL_SEC > 0`)与灰度档
|
|
122
|
+
* `RETENTION_MODE=enforce`(「按策略删」);齐 = 有视界(`RETENTION_MAX_AGE_DAYS`,算 cutoff)且节律 > 0(车道真在跑)。缺一 ⇒ 拒:
|
|
123
|
+
* enforce 而车道不跑 / 没有视界,运维以为在删而什么都没删(能力位 `retention` 只在车道齐时在场);节律在而没有视界,车道每拍枚举域、什么都算不出。
|
|
124
|
+
* 一条规则两种要法,拒句按要法说出路(enforce:补缺的键,或改回 audit-only —— 节律在而天数缺时连节律一起设 0;只给节律:补天数或节律设 0),
|
|
125
|
+
* 每条出路照做都落在本律之内(起得来)。audit-only 下「天数在、车道关」不在律内 ——
|
|
126
|
+
* 那只是一份声明,起服 warn `retention_policy_not_executed` 说出来(`boot/governance-seams.ts`)。车道的**接线**(执行器 / 方法 / 店声明)不是配置事实,
|
|
127
|
+
* 留在扫车道自持门(`boot/retention-lane.ts`)。状态型:三键都只来自 env、运行期无写点 ⇒ 热路径上恒与 boot 同答。
|
|
128
|
+
*/
|
|
129
|
+
export declare function retentionLaneRefusal(v: Pick<CrossInvariantView, "retentionPolicy" | "retentionSweep">): string | undefined;
|
|
110
130
|
export declare const CONFIG_CROSS_INVARIANTS: readonly CrossInvariant[];
|
|
111
131
|
/**
|
|
112
132
|
* 按 id 取**一条**([ref]②:boot 面的单源化出口)。
|
|
@@ -103,6 +103,34 @@ export function centerIdentityRefusal(v) {
|
|
|
103
103
|
`the same web-admin: same host and port (http and https on one host count as one). Set ${WEB_ADMIN_ENV.webUrl} to that web-admin's console, set ` +
|
|
104
104
|
`AUTH_BRIDGE_ISSUER to the web-admin's public origin, or unset ${WEB_ADMIN_ENV.webUrl}. Refusing to boot.`);
|
|
105
105
|
}
|
|
106
|
+
export function remoteConfigProviderUrlRefusal(v) {
|
|
107
|
+
return v.configProvider === "remote" && v.webAdmin === undefined
|
|
108
|
+
? `CONFIG_PROVIDER=remote names the web-admin center as this worker's config source, but ${WEB_ADMIN_ENV.url} is not set — there is no center to pull ` +
|
|
109
|
+
"from, so this worker would run without the center's configuration (tenant entitlements, model catalog, governance) while it is declared centrally managed. " +
|
|
110
|
+
`Set ${WEB_ADMIN_ENV.url} to the center's base URL, or set CONFIG_PROVIDER=local to read the local config directory (unset CONFIG_PROVIDER for an env-only worker). ` +
|
|
111
|
+
"Refusing to boot."
|
|
112
|
+
: undefined;
|
|
113
|
+
}
|
|
114
|
+
export function retentionLaneRefusal(v) {
|
|
115
|
+
const { mode, intervalSec } = v.retentionSweep;
|
|
116
|
+
const cadence = intervalSec > 0;
|
|
117
|
+
const horizon = v.retentionPolicy !== undefined;
|
|
118
|
+
if ((mode !== "enforce" && !cadence) || (cadence && horizon))
|
|
119
|
+
return undefined;
|
|
120
|
+
const gaps = [
|
|
121
|
+
...(horizon ? [] : ["RETENTION_MAX_AGE_DAYS is unset (no horizon to compute a cutoff from)"]),
|
|
122
|
+
...(cadence ? [] : ["RETENTION_SWEEP_INTERVAL_SEC is unset or 0 (the sweep lane does not run)"]),
|
|
123
|
+
].join(" and ");
|
|
124
|
+
if (mode === "enforce") {
|
|
125
|
+
const needs = [...(horizon ? [] : ["RETENTION_MAX_AGE_DAYS"]), ...(cadence ? [] : ["RETENTION_SWEEP_INTERVAL_SEC above 0"])].join(" and ");
|
|
126
|
+
const declareOnly = cadence && !horizon ? "set RETENTION_MODE=audit-only (or unset it) and RETENTION_SWEEP_INTERVAL_SEC=0" : "set RETENTION_MODE=audit-only (or unset it)";
|
|
127
|
+
return (`RETENTION_MODE=enforce declares that the retention sweep lane deletes data older than the policy horizon, but ${gaps} — nothing would be deleted ` +
|
|
128
|
+
`while the deployment declares that it deletes. Set ${needs} (the sweep lane runs on a SQL backend), or ${declareOnly} ` +
|
|
129
|
+
"if this deployment is not to delete. Refusing to boot.");
|
|
130
|
+
}
|
|
131
|
+
return (`RETENTION_SWEEP_INTERVAL_SEC=${intervalSec} arms the retention sweep lane, but ${gaps} — the lane would enumerate domains every tick and compute nothing. ` +
|
|
132
|
+
"Set RETENTION_MAX_AGE_DAYS, or set RETENTION_SWEEP_INTERVAL_SEC=0 to leave the lane off. Refusing to boot.");
|
|
133
|
+
}
|
|
106
134
|
export const CONFIG_CROSS_INVARIANTS = [
|
|
107
135
|
{
|
|
108
136
|
id: "run-stale-heartbeat",
|
|
@@ -297,6 +325,20 @@ export const CONFIG_CROSS_INVARIANTS = [
|
|
|
297
325
|
bootAnchor: { file: "src/config.ts", marker: "CROSS-INVARIANT:center-one-identity" },
|
|
298
326
|
check: ({ next }) => centerIdentityRefusal(next),
|
|
299
327
|
},
|
|
328
|
+
{
|
|
329
|
+
id: "remote-config-provider-url",
|
|
330
|
+
keys: ["configProvider", "webAdmin"],
|
|
331
|
+
restartReason: "config-source",
|
|
332
|
+
bootAnchor: { file: "src/config.ts", marker: "CROSS-INVARIANT:remote-config-provider-url" },
|
|
333
|
+
check: ({ next }) => remoteConfigProviderUrlRefusal(next),
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
id: "retention-lane-complete",
|
|
337
|
+
keys: ["retentionPolicy", "retentionSweep"],
|
|
338
|
+
restartReason: "retention-lane",
|
|
339
|
+
bootAnchor: { file: "src/config.ts", marker: "CROSS-INVARIANT:retention-lane-complete" },
|
|
340
|
+
check: ({ next }) => retentionLaneRefusal(next),
|
|
341
|
+
},
|
|
300
342
|
];
|
|
301
343
|
export function crossInvariant(id) {
|
|
302
344
|
const inv = CONFIG_CROSS_INVARIANTS.find((i) => i.id === id);
|
|
@@ -120,12 +120,12 @@ export interface ConfigProviderInput {
|
|
|
120
120
|
};
|
|
121
121
|
/** `CONFIG_PROVIDER` —— 闭集 `local` | `remote` | 缺席([ref]:词表属主 `CONFIG_PROVIDER_WORDS`,认不出的词在
|
|
122
122
|
* `loadConfig` 就拒启,本层**不可能**再收到第三个词 —— 修前那条「认不出 ⇒ 当 local + warn」的臂随之删除)。
|
|
123
|
-
*
|
|
123
|
+
* 读法只有 {@link configSourceKind} 一只:`local` 建本地源;`remote` 建中心源(没有 `webAdmin` ⇒ 抛,起服本应已拒);缺席 ⇒ 有中心建中心源、没有 ⇒ 抛(纯 env 部署不建配置源)。 */
|
|
124
124
|
provider?: ConfigProviderWord;
|
|
125
125
|
/** 本地配置源的根(持有 `config.d/<domain>.json`;FileConfigStore 吃根、读 `<root>/config.d`)。🔴 [ref]:**必填**,
|
|
126
126
|
* 值恒来自 {@link configLocalRoot}(入口算一次,工厂与执行车道合成步读同一个)—— 修前是可选、缺席回落
|
|
127
127
|
* `process.cwd()`,而工厂只在 `CONFIG_PROVIDER === "local"` 字面上递它 ⇒ 另一条走到 local 的路上配置源读 cwd、
|
|
128
|
-
* 合成步读 localRoot
|
|
128
|
+
* 合成步读 localRoot,两个根分家。远程源也收它(入参形一份),只有本地源读它。 */
|
|
129
129
|
localDir: string;
|
|
130
130
|
/** [ref]:本地配置源的属主声明(`CONFIG_LOCAL_OWNER_UID`,配置席 `configLocalOwnerUid`)—— 每拍读 `config.d` 之前的目录信任判官与起服那一次判同一个值。
|
|
131
131
|
* **必填**(值可以是 `undefined` = 没声明):两个生产构造点都必须递,漏递 = 起服判过、每拍却按「没声明」判 ⇒ 每一拍都拒(tsc 在这里挡)。 */
|
|
@@ -186,15 +186,11 @@ export declare class LocalConfigProvider implements ConfigProvider {
|
|
|
186
186
|
*/
|
|
187
187
|
export declare function mapToServiceEffective(eff: AgentConfigEffective, version: number): EffectiveConfig;
|
|
188
188
|
/**
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
* `
|
|
193
|
-
*
|
|
194
|
-
* under the old code path; local-with-empty-config.d degrades to env the same way). An UNRECOGNIZED value
|
|
195
|
-
* never reaches this function: `loadConfig` refuses to boot on it ([ref]), so a fat-fingered knob can
|
|
196
|
-
* neither source config from an unintended network endpoint nor be read as "local" here while the
|
|
197
|
-
* execution-lane default reads it as "not local".
|
|
189
|
+
* 建判官 {@link configSourceKind} 答出来的那一种配置源:`local` ⇒ {@link LocalConfigProvider}(根 = 递进来的 `localDir`);`remote` ⇒
|
|
190
|
+
* {@link RemoteConfigProvider}(中心 = `webAdmin`)。判官答「无配置源」(没写词、没配中心 = 纯 env 部署)⇒ 抛:调用方只在判官答 local / remote 时建
|
|
191
|
+
* (服务端第 2 段先问判官;run-local 在入口只放过 `local` 的词)。没有第三种读法 —— 「remote 而没有中心 ⇒ 落回本地」那一臂已删(配置源的词要么兑现、要么拒;
|
|
192
|
+
* 起服在 `loadConfig` 的配置不变量段拒这一组合,到得了这里 = 绕过了 `loadConfig`,判官抛起服拒的同一句)。认不出的词同样到不了这里:
|
|
193
|
+
* `loadConfig` 拒启([ref]),入参型是闭集。
|
|
198
194
|
*/
|
|
199
195
|
export declare function createConfigProvider(input: ConfigProviderInput): ConfigProvider;
|
|
200
196
|
/**
|
|
@@ -209,21 +205,20 @@ export declare function createConfigProvider(input: ConfigProviderInput): Config
|
|
|
209
205
|
export declare function configLocalRoot(config: {
|
|
210
206
|
readonly configLocalDir?: string | undefined;
|
|
211
207
|
}): string;
|
|
208
|
+
/** 配置源的两种形态(纯 env 部署没有配置源 —— 判官答 `undefined`)。 */
|
|
209
|
+
export type ConfigSourceKind = "local" | "remote";
|
|
212
210
|
/**
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
* `local`
|
|
211
|
+
* 这台进程的配置源是**哪一种** —— 判据的唯一属主(一个问题一个读者):HTTP 服务第 2 段(目录信任 + 一次性迁移、执行车道合成步)、
|
|
212
|
+
* web-admin 工厂与 {@link createConfigProvider}(run-local 经它;run-local 在入口只放过 `local` 的词)都问这一只。规则一条 —— 配置源的词要么兑现、要么拒:
|
|
213
|
+
* · `CONFIG_PROVIDER=local` ⇒ `local`(配没配中心都是;中心照样管 fleet 面);
|
|
214
|
+
* · `CONFIG_PROVIDER=remote` ⇒ `remote`;没有中心 ⇒ **抛**起服拒的同一句(`remoteConfigProviderUrlRefusal`;`loadConfig` 的配置不变量段本应已拒,
|
|
215
|
+
* 到得了这里 = 绕过了它)—— 修前这一形在两只判官里各被读成一种别的源(服务端「无配置源」、构造器「local」),零句;
|
|
216
|
+
* · 不写词 ⇒ 有中心 `remote`、没有 `undefined`(纯 env 部署,不建配置源)。
|
|
217
|
+
* 修前是两只判官(`configProviderKind` 答 local | remote、`serviceConfigSourceKind` 包一层答 local | remote | 无),对「不写词、没配中心」一只答 local、
|
|
218
|
+
* 一只答无;收成这一只,两名删除。
|
|
216
219
|
*/
|
|
217
|
-
export declare function
|
|
218
|
-
readonly provider?: ConfigProviderWord | undefined;
|
|
219
|
-
readonly webAdmin?: unknown;
|
|
220
|
-
}): "local" | "remote";
|
|
221
|
-
/**
|
|
222
|
-
* HTTP 服务这一侧的配置源:web-admin 工厂**建不建** provider(`CONFIG_PROVIDER=local` 或配了中心才建)、建出来是哪一种。
|
|
223
|
-
* `undefined` = 纯 env 部署(没有配置源)。工厂与执行车道合成步读这同一只(车PI 修复轮 ①:合成步排在工厂之前)。
|
|
224
|
-
*/
|
|
225
|
-
export declare function serviceConfigSourceKind(config: {
|
|
220
|
+
export declare function configSourceKind(config: {
|
|
226
221
|
readonly configProvider?: ConfigProviderWord | undefined;
|
|
227
222
|
readonly webAdmin?: unknown;
|
|
228
|
-
}):
|
|
223
|
+
}): ConfigSourceKind | undefined;
|
|
229
224
|
//# sourceMappingURL=config-provider.d.ts.map
|
package/dist/config-provider.js
CHANGED
|
@@ -6,6 +6,7 @@ import { assertLocalConfigDirTrusted } from "./config-dir-trust.js";
|
|
|
6
6
|
import { danglingRefs, emptyEffective, findSkillContent, promptArtifactFor, renderRefIssue, skillContentHash, } from "@sema-agent/settings-schema";
|
|
7
7
|
import { redactSecrets } from "./trace/redact.js";
|
|
8
8
|
import { fetchEffective as remoteFetchEffective, fetchSkillContent as remoteFetchSkillContent, skillToolListsOf, WebAdminHttpError, } from "./web-admin-client/facade.js";
|
|
9
|
+
import { remoteConfigProviderUrlRefusal } from "./config-invariants.js";
|
|
9
10
|
import { homedir } from "node:os";
|
|
10
11
|
import { join } from "node:path";
|
|
11
12
|
const OPERAND_FINGERPRINT_KEY = randomBytes(16);
|
|
@@ -205,6 +206,8 @@ export function mapToServiceEffective(eff, version) {
|
|
|
205
206
|
...readMcpSourceLabel(s.name, s.source),
|
|
206
207
|
...(s.toolFaces !== undefined ? { toolFaces: s.toolFaces } : {}),
|
|
207
208
|
...(s.toolAxes !== undefined ? { toolAxes: s.toolAxes } : {}),
|
|
209
|
+
...(s.sessionMetaKey !== undefined ? { sessionMetaKey: s.sessionMetaKey } : {}),
|
|
210
|
+
...(s.startupTimeoutMs !== undefined ? { startupTimeoutMs: s.startupTimeoutMs } : {}),
|
|
208
211
|
...(s.authForm !== undefined ? { authForm: s.authForm } : {}),
|
|
209
212
|
...(s.entryKind !== undefined ? { entryKind: s.entryKind } : {}),
|
|
210
213
|
};
|
|
@@ -248,21 +251,33 @@ export function mapToServiceEffective(eff, version) {
|
|
|
248
251
|
};
|
|
249
252
|
}
|
|
250
253
|
export function createConfigProvider(input) {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
+
const kind = configSourceKind({ configProvider: input.provider, webAdmin: input.webAdmin });
|
|
255
|
+
if (kind === "local")
|
|
256
|
+
return new LocalConfigProvider(input.localDir, undefined, { declaredOwnerUid: input.localOwnerUid });
|
|
257
|
+
if (kind === "remote" && input.webAdmin !== undefined)
|
|
258
|
+
return new RemoteConfigProvider(input.webAdmin, {}, input.skillBodyCacheDir);
|
|
259
|
+
throw new Error(`createConfigProvider: no config source to build (CONFIG_PROVIDER is unset and no center is configured — an env-only deployment). ` +
|
|
260
|
+
`Build a provider only when configSourceKind answers "local" or "remote".`);
|
|
254
261
|
}
|
|
255
262
|
export function configLocalRoot(config) {
|
|
256
263
|
return config.configLocalDir ?? process.env.AGENT_DATA_DIR ?? join(homedir(), ".ai-agent");
|
|
257
264
|
}
|
|
258
|
-
export function
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
265
|
+
export function configSourceKind(config) {
|
|
266
|
+
switch (config.configProvider) {
|
|
267
|
+
case "local":
|
|
268
|
+
return "local";
|
|
269
|
+
case "remote": {
|
|
270
|
+
const refusal = remoteConfigProviderUrlRefusal(config);
|
|
271
|
+
if (refusal !== undefined)
|
|
272
|
+
throw new Error(refusal);
|
|
273
|
+
return "remote";
|
|
274
|
+
}
|
|
275
|
+
case undefined:
|
|
276
|
+
return config.webAdmin !== undefined ? "remote" : undefined;
|
|
277
|
+
default: {
|
|
278
|
+
const unreachable = config.configProvider;
|
|
279
|
+
throw new Error(`configSourceKind: CONFIG_PROVIDER word outside the closed set: ${String(unreachable)}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
267
282
|
}
|
|
268
283
|
//# sourceMappingURL=config-provider.js.map
|
package/dist/config-types.d.ts
CHANGED
|
@@ -936,7 +936,9 @@ export interface ServiceConfigFlat {
|
|
|
936
936
|
token?: string;
|
|
937
937
|
caCert?: string;
|
|
938
938
|
insecureTls?: boolean;
|
|
939
|
-
namespace
|
|
939
|
+
/** `K8S_NAMESPACE` — the namespace the sandbox pods live in. REQUIRED, no default: the loader refuses to start when `REMOTE_EXEC=k8s` names the
|
|
940
|
+
* lane without it, so this arm never carries an absent namespace and no consumer needs a fallback of its own. */
|
|
941
|
+
namespace: string;
|
|
940
942
|
runtimeClass?: string;
|
|
941
943
|
mountPath?: string;
|
|
942
944
|
timeoutMs?: number;
|
|
@@ -1312,15 +1314,16 @@ export interface ServiceConfigFlat {
|
|
|
1312
1314
|
*
|
|
1313
1315
|
* 🔴 语义边界(成文,别当成"数据会被删"):core **只**拿它做启动期能力校验(锁着 + 店未声明
|
|
1314
1316
|
* `retention:"managed"` ⇒ 拒启),引擎自己在任务路径上从不删数据;真执行(调度/重试/副本协调/审计)
|
|
1315
|
-
*
|
|
1316
|
-
*
|
|
1317
|
+
* 是部署侧的活 —— 扫车道(`retentionSweep`,`boot/retention-lane.ts`)。配了策略而扫车道关着(只可能在 `audit-only` 档:
|
|
1318
|
+
* `enforce` 而车道不齐起服拒,配置不变量 `retention-lane-complete`)时,启动会打一条 `retention_policy_not_executed` 的响亮 warn。
|
|
1317
1319
|
*/
|
|
1318
1320
|
retentionPolicy?: RetentionPolicy;
|
|
1319
1321
|
/**
|
|
1320
1322
|
* [ref] 车2 —— 托管留存 **sweep lane** 的两个旋钮(设计稿 `DESIGN-270-retention-lane.md` §3/§4)。
|
|
1321
1323
|
* `retentionPolicy` 说的是「保留多久」(一句声明),本格说的是「谁在什么节律上按那句话删」。
|
|
1322
1324
|
* **恒在场**(不是可选块):两根都有文档化的缺省,而缺省本身是一条要能被读出来的姿态 ——
|
|
1323
|
-
* `{mode:"audit-only", intervalSec:0}` = 「lane
|
|
1325
|
+
* `{mode:"audit-only", intervalSec:0}` = 「lane 关着,真开起来也先只记账」。被要的车道必须齐(`intervalSec > 0` 或 `mode:"enforce"` ⇒
|
|
1326
|
+
* 视界与 > 0 的节律都在,否则起服拒 —— 配置不变量 `retention-lane-complete`)。
|
|
1324
1327
|
*/
|
|
1325
1328
|
retentionSweep: RetentionSweepConfig;
|
|
1326
1329
|
/** Tool names that require operator approval before running (F4). Empty = no approval gate. */
|
|
@@ -2267,8 +2270,10 @@ export interface ServiceConfigFlat {
|
|
|
2267
2270
|
* 传输上界)与 `CENTER_CREDENTIAL_RENEW_LEAD_MAX_MS`(访问令牌寿命之半)之间,坏值拒启(解析口 `parseCenterCredentialRenewLeadMs`)。
|
|
2268
2271
|
* 裸行文件 / `SEMA_WEB_ADMIN_TOKEN` 值形不受它影响(不续签)。`CENTER_CREDENTIAL_RENEW_LEAD_MS`。 */
|
|
2269
2272
|
centerCredentialRenewLeadMs: number;
|
|
2270
|
-
/** Dual-mode config SOURCE (DUAL-MODE-DESIGN §4): "remote" (web-admin HTTP
|
|
2273
|
+
/** Dual-mode config SOURCE (DUAL-MODE-DESIGN §4): "remote" (web-admin HTTP; needs SEMA_WEB_ADMIN_URL — remote without it
|
|
2274
|
+
* refuses to boot, cross-invariant `remote-config-provider-url`) | "local" (.env + config.d
|
|
2271
2275
|
* via @sema-agent/settings-schema FileConfigStore) | unset → remote if SEMA_WEB_ADMIN_URL is set, else pure-env.
|
|
2276
|
+
* One reader: `configSourceKind` (config-provider.ts).
|
|
2272
2277
|
* Env: CONFIG_PROVIDER —— [ref] 起闭集 {@link CONFIG_PROVIDER_WORDS}(认不出的词拒启;空串 = 未设)。
|
|
2273
2278
|
* The same resolver/EffectiveConfig either way (can't drift). */
|
|
2274
2279
|
configProvider?: ConfigProviderWord;
|