@sema-agent/server 7.50.0 → 7.52.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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +83 -20
- package/dist/adoption/plan.d.ts +4 -4
- package/dist/adoption/plan.js +11 -0
- package/dist/approval-card.d.ts +26 -2
- package/dist/approval-card.js +9 -0
- package/dist/approval-hmac.d.ts +1 -1
- package/dist/approval-reconciler.d.ts +2 -2
- package/dist/approval-reconciler.js +1 -1
- package/dist/bench/l8/artifact.d.ts +1 -1
- package/dist/bench/s1/arms.d.ts +1 -1
- package/dist/bench/s1/live-deps.d.ts +1 -1
- package/dist/bench/s1/oracle.d.ts +1 -1
- package/dist/bench/s1/row.d.ts +1 -1
- package/dist/boot/budget-tracing.d.ts +1 -1
- package/dist/boot/budget-tracing.js +2 -5
- package/dist/boot/coordinators.js +3 -1
- package/dist/boot/deferred-sandbox-path-env.d.ts +1 -1
- package/dist/boot/device-lane.d.ts +79 -0
- package/dist/boot/device-lane.js +63 -0
- package/dist/boot/engine-lease.d.ts +1 -1
- package/dist/boot/execution-env.d.ts +48 -2
- package/dist/boot/execution-env.js +57 -5
- package/dist/boot/governance-seams.d.ts +2 -2
- package/dist/boot/leader.d.ts +1 -1
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-consolidation.d.ts +6 -6
- package/dist/boot/org-memory.d.ts +1 -1
- package/dist/boot/parked-revive-gate.d.ts +3 -3
- package/dist/boot/reapers.d.ts +2 -2
- package/dist/boot/reapers.js +17 -4
- package/dist/boot/resolve-spec.d.ts +15 -0
- package/dist/boot/resolve-spec.js +40 -15
- package/dist/boot/retention-lane.d.ts +2 -2
- package/dist/boot/runner-deps.d.ts +17 -7
- package/dist/boot/runner-deps.js +4 -2
- package/dist/boot/runtime-caps.d.ts +23 -0
- package/dist/boot/runtime-caps.js +24 -2
- package/dist/boot/session-faces.d.ts +6 -1
- package/dist/boot/session-faces.js +17 -3
- package/dist/boot/shutdown.d.ts +8 -0
- package/dist/boot/shutdown.js +3 -1
- package/dist/boot/stores.js +40 -1
- package/dist/boot/task-list-lane.d.ts +2 -2
- package/dist/brain.js +51 -31
- package/dist/budget.d.ts +2 -2
- package/dist/capabilities/center-plugins.d.ts +1 -1
- package/dist/capabilities/collab-workflows.d.ts +1 -1
- package/dist/capabilities/hands-lane.d.ts +3 -3
- package/dist/capabilities/scenarios.d.ts +3 -3
- package/dist/capabilities/skills.d.ts +1 -1
- package/dist/config-center/hot-keys-registry.js +5 -0
- package/dist/config-center/http-client.d.ts +2 -2
- package/dist/config-center/read-face.d.ts +1 -1
- package/dist/config-center/restart-signal.d.ts +1 -1
- package/dist/config-center/types.d.ts +10 -3
- package/dist/config-invariants.d.ts +2 -2
- package/dist/config-invariants.js +18 -0
- package/dist/config-types.d.ts +90 -18
- package/dist/config.js +91 -19
- package/dist/deployment-governance.d.ts +1 -1
- package/dist/device-enrollment.d.ts +125 -0
- package/dist/device-enrollment.js +156 -0
- package/dist/device-store.d.ts +385 -0
- package/dist/device-store.js +407 -0
- package/dist/device-ws-hub.d.ts +182 -0
- package/dist/device-ws-hub.js +1012 -0
- package/dist/device-ws-protocol.d.ts +429 -0
- package/dist/device-ws-protocol.js +464 -0
- package/dist/env-facts.d.ts +5 -2
- package/dist/env-facts.js +1 -0
- package/dist/execution-lane-caps.d.ts +152 -0
- package/dist/execution-lane-caps.js +166 -0
- package/dist/fleet/fleet-bus.d.ts +1 -1
- package/dist/fleet/fleet-reconciler.d.ts +1 -1
- package/dist/fleet/fleet-terminal-window.d.ts +1 -1
- package/dist/http/active-run-conflict.d.ts +2 -2
- package/dist/http/principal-gate.d.ts +1 -1
- package/dist/http/route-ctx.d.ts +24 -4
- package/dist/http/routes/admin-memory-optout.d.ts +48 -0
- package/dist/http/routes/admin-memory-optout.js +75 -0
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/approvals-assistant.js +21 -21
- package/dist/http/routes/capabilities.js +27 -11
- package/dist/http/routes/diagnostics.d.ts +1 -1
- package/dist/http/routes/leader.d.ts +1 -1
- package/dist/http/routes/memory-bundle.d.ts +1 -1
- package/dist/http/routes/memory-bundle.js +3 -1
- package/dist/http/routes/memory-compliance.d.ts +4 -4
- package/dist/http/routes/memory-origin.d.ts +4 -4
- package/dist/http/routes/memory-origin.js +3 -1
- package/dist/http/routes/memory-policy.js +6 -2
- package/dist/http/routes/retention-ops.d.ts +1 -1
- package/dist/http/routes/rules.d.ts +5 -2
- package/dist/http/routes/rules.js +84 -5
- package/dist/http/routes/run-memory-capture.d.ts +34 -0
- package/dist/http/routes/run-memory-capture.js +97 -0
- package/dist/http/routes/runs.d.ts +1 -0
- package/dist/http/routes/runs.js +212 -6
- package/dist/http/routes/session-sync.d.ts +4 -6
- package/dist/http/routes/session-sync.js +60 -47
- package/dist/http/routes/sessions.js +61 -188
- package/dist/http/routes/shared-memory.d.ts +1 -1
- package/dist/http/routes/tasks.js +1 -1
- package/dist/http/routes/workflows.js +19 -0
- package/dist/http/server.d.ts +49 -13
- package/dist/http/server.js +109 -13
- package/dist/http/verify-rounds.d.ts +1 -1
- package/dist/http/wire-types.d.ts +41 -8
- package/dist/leader/endpoint.d.ts +1 -1
- package/dist/leader/leader.d.ts +1 -1
- package/dist/leader/repair-oracle.d.ts +2 -2
- package/dist/leader/repair-oracle.js +1 -1
- package/dist/leader/wire.js +4 -2
- package/dist/main.js +23 -9
- package/dist/memory-bundle-engine.d.ts +1 -1
- package/dist/memory-operator-faces.d.ts +5 -5
- package/dist/memory-origin-fence.d.ts +50 -0
- package/dist/memory-origin-fence.js +15 -0
- package/dist/memory-posture.d.ts +13 -1
- package/dist/memory-posture.js +1 -0
- package/dist/memory-scope.d.ts +6 -1
- package/dist/memory-scope.js +3 -2
- package/dist/model-select.d.ts +2 -2
- package/dist/observability/fail-open.d.ts +17 -5
- package/dist/observability/fail-open.js +17 -5
- package/dist/orchestration/hardened-vm-runner.d.ts +9 -2
- package/dist/orchestration/hardened-vm-runner.js +11 -1
- package/dist/orchestration/hardened-vm-worker-runner.js +2 -2
- package/dist/orchestration/workflow-completion-inbox.d.ts +2 -2
- package/dist/plugins/background-shell-support.d.ts +2 -2
- package/dist/plugins/blob-backend.d.ts +7 -2
- package/dist/plugins/blob-backend.js +22 -18
- package/dist/plugins/caching-session-store.d.ts +7 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +2 -2
- package/dist/plugins/device-store-sql.d.ts +130 -0
- package/dist/plugins/device-store-sql.js +574 -0
- package/dist/plugins/file-history-store-sql.d.ts +170 -0
- package/dist/plugins/file-history-store-sql.js +827 -0
- package/dist/plugins/file-run-store.d.ts +44 -5
- package/dist/plugins/file-run-store.js +85 -13
- package/dist/plugins/fork-routing-session-store.d.ts +1 -1
- package/dist/plugins/fork-routing-session-store.js +2 -2
- package/dist/plugins/leader-run-store-sql.d.ts +1 -1
- package/dist/plugins/local-session-store.d.ts +9 -1
- package/dist/plugins/memory-embedder-fingerprint.d.ts +1 -1
- package/dist/plugins/memory-optout-grant-store-sql.d.ts +139 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +157 -0
- package/dist/plugins/memory-origin-law.d.ts +2 -2
- package/dist/plugins/memory-run-store.d.ts +4 -3
- package/dist/plugins/memory-run-store.js +2 -1
- package/dist/plugins/permission-rule-store-file.d.ts +16 -6
- package/dist/plugins/permission-rule-store-file.js +77 -13
- package/dist/plugins/permission-rule-store-sql.d.ts +156 -8
- package/dist/plugins/permission-rule-store-sql.js +123 -21
- package/dist/plugins/pg-pool.js +59 -0
- package/dist/plugins/pg-safe-json.d.ts +1 -1
- package/dist/plugins/remote-env-device.d.ts +271 -0
- package/dist/plugins/remote-env-device.js +727 -0
- package/dist/plugins/remote-env-k8s.d.ts +1 -1
- package/dist/plugins/remote-scratchpad.js +1 -1
- package/dist/plugins/retention-lane-store-sql.d.ts +3 -3
- package/dist/plugins/retention-store-sql.d.ts +7 -7
- package/dist/plugins/retention-store-sql.js +6 -0
- package/dist/plugins/run-store-sql.d.ts +9 -3
- package/dist/plugins/run-store-sql.js +2 -2
- package/dist/plugins/send-user-file.d.ts +1 -1
- package/dist/plugins/session-placement.d.ts +1 -1
- package/dist/plugins/sql-errors.d.ts +1 -1
- package/dist/plugins/store-backend.d.ts +68 -29
- package/dist/plugins/store-backend.js +78 -15
- package/dist/plugins/store-contracts.d.ts +5 -3
- package/dist/plugins/task-list-store-sql.d.ts +1 -1
- package/dist/plugins/tidb-pool.js +59 -0
- package/dist/plugins/web-search.d.ts +1 -1
- package/dist/prompts-domain-validate.js +1 -1
- package/dist/resource-suspend.d.ts +1 -1
- package/dist/resource-window.d.ts +3 -3
- package/dist/rules-consent.d.ts +231 -9
- package/dist/rules-consent.js +411 -13
- package/dist/run-local.js +1 -0
- package/dist/runs.d.ts +15 -1
- package/dist/runs.js +19 -0
- package/dist/runtime-caps-resolver.d.ts +36 -1
- package/dist/runtime-caps-resolver.js +25 -0
- package/dist/runtime-governance.d.ts +1 -1
- package/dist/security.d.ts +5 -5
- package/dist/security.js +1 -1
- package/dist/session-sync.d.ts +52 -37
- package/dist/session-sync.js +19 -16
- package/dist/shared-memory-scope-authorizer.d.ts +1 -1
- package/dist/sighup-idle.d.ts +1 -1
- package/dist/spec-fields.d.ts +22 -1
- package/dist/spec-fields.js +11 -0
- package/dist/store-live-probe.d.ts +2 -2
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-cwd.d.ts +25 -0
- package/dist/task-cwd.js +3 -0
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-settings.d.ts +3 -3
- package/dist/task-settings.js +3 -1
- package/dist/task-workflow.d.ts +1 -1
- package/dist/text-bidi.d.ts +2 -2
- package/dist/tool-approval.d.ts +191 -9
- package/dist/tool-approval.js +248 -29
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/engine-notice-wire.d.ts +6 -4
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/ledger-events.d.ts +1 -1
- package/dist/trace/ledger-sink.d.ts +2 -2
- package/dist/trace/project.d.ts +3 -2
- package/dist/trace/project.js +1 -0
- package/dist/turn-activity.d.ts +1 -1
- package/dist/wall-clock-jump-guard.d.ts +3 -3
- package/package.json +2 -2
- package/dist/http/tar.d.ts +0 -17
- package/dist/http/tar.js +0 -53
- package/dist/http/workspace-content.d.ts +0 -11
- package/dist/http/workspace-content.js +0 -20
- package/dist/plugins/file-snapshot-store-sql.d.ts +0 -170
- package/dist/plugins/file-snapshot-store-sql.js +0 -213
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { realpathSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { NodeExecutionEnv, QUESTION_AWAITS_RESUME, expandTiers, tightenTaskSpec } from "@sema-agent/core";
|
|
3
|
+
import { NodeExecutionEnv, QUESTION_AWAITS_RESUME, deriveAskEffective, expandTiers, resolveAskSeamForm, tightenTaskSpec } from "@sema-agent/core";
|
|
4
4
|
import { cappedCeiling } from "../budget.js";
|
|
5
5
|
import { centerPromptProvider, centerIdentityAssembled } from "../capabilities/center-prompts.js";
|
|
6
6
|
import { SessionEnvironmentSelection, selectEnvironmentTool } from "../capabilities/select-environment-tool.js";
|
|
@@ -13,6 +13,7 @@ import { assertGuardPatternsUsable, buildOnlySensitiveBaselineWarning, createApp
|
|
|
13
13
|
import { acceptShellScratchpadDir, buildEnvFacts, egressForRemoteExec, ensureScratchpadDir, resumeFactsForLane } from "../env-facts.js";
|
|
14
14
|
import { FleetEventBus } from "../fleet/fleet-bus.js";
|
|
15
15
|
import { composeHooks, createTaskHooks } from "../hooks/hook-runner.js";
|
|
16
|
+
import { headerStr } from "../http/principal-gate.js";
|
|
16
17
|
import { explicitOperatorOk } from "../http/server.js";
|
|
17
18
|
import { isModelAllowlisted, matchCatalogModel, modelSupportsImages, resolveTaskModel, terminalCatalogName } from "../model-select.js";
|
|
18
19
|
import { PerTaskImageRegistry, resolveSandboxImageRef } from "../per-task-image.js";
|
|
@@ -26,7 +27,7 @@ import { HttpError, encodeCheckpointScope } from "../security.js";
|
|
|
26
27
|
import { memorySpecForRequest } from "../memory-scope.js";
|
|
27
28
|
import { a2aForScenario, mcpForScenario } from "../config-center/facade.js";
|
|
28
29
|
import { normalizeAttachments, normalizeResilience, normalizeResumeAtMode, normalizeSuggestNextPrompts, promptProfileFromBody, resolveTaskLimits, retainBackgroundProcessesFromBody, taskAgentsSpecFragment, toolMaterializeStrategyFromBody, toolNameListFromBody } from "../spec-fields.js";
|
|
29
|
-
import { cwdHonored, effectiveHostWorkspace, inProcessSingleUserLane, isValidCwd, parseAdditionalDirectories, satisfiedByProcessCwd, shellEnvMismatchCount } from "../task-cwd.js";
|
|
30
|
+
import { cwdHonored, deviceCwdHonored, effectiveHostWorkspace, inProcessSingleUserLane, isValidCwd, parseAdditionalDirectories, satisfiedByProcessCwd, shellEnvMismatchCount } from "../task-cwd.js";
|
|
30
31
|
import { assertRequestA2aUnlocked, resolveRequestA2a } from "../task-a2a.js";
|
|
31
32
|
import { assertRequestMcpContentOrigin, assertRequestMcpUnlocked, resolveRequestMcp } from "../task-mcp.js";
|
|
32
33
|
import { MAX_SETTINGS_OUTPUT_STYLE_CHARS, acceptAppendSystemPrompt, applyTaskSettings, effectivePermissionMode, effectiveThinking, hasConstitutionAnchors, parseTaskSettings, providerDropsAppend, shellGateForMode, withPermissionMode } from "../task-settings.js";
|
|
@@ -35,21 +36,25 @@ import { redactSecrets } from "../trace/redact.js";
|
|
|
35
36
|
import { DeferredSandboxPathEnv, isSandboxPathAdjudicationLane, sandboxPathEnvSlots } from "./deferred-sandbox-path-env.js";
|
|
36
37
|
import { effectiveMemoryPersistenceCapable } from "./memory-boundary.js";
|
|
37
38
|
export function createResolveSpec(ctx) {
|
|
38
|
-
const { config, logger, metrics, localRoot, scenarios, principalCaps, centerRuntimeCapsResolver, handsLanes, getCenterPrompts, getKeyResolver, taskAttachmentStore, perSessionCwd, setSessionCwd, setSessionShellEnv, hookLlm, hookAgent, fleetBus, hookWakeBus, resumeAnchorStore, ownerAware, taskLimitCaps, taskTimeoutSec, selectEnvTool, sendUserFileToolSpec, memoryEngine, durableEnabled, approvalExemptionStore, singleUserAutoAcceptBaseline, checkpointStore, deploymentHooks, imageIndex, perTaskImage, sessionEnvSelection, liveQuestionFace, lockedKeys, } = ctx;
|
|
39
|
+
const { config, logger, metrics, localRoot, scenarios, principalCaps, centerRuntimeCapsResolver, handsLanes, getCenterPrompts, getKeyResolver, taskAttachmentStore, perSessionCwd, setSessionCwd, setSessionShellEnv, fenceSessionOwner, hookLlm, hookAgent, fleetBus, hookWakeBus, resumeAnchorStore, ownerAware, taskLimitCaps, taskTimeoutSec, selectEnvTool, sendUserFileToolSpec, memoryEngine, durableEnabled, approvalExemptionStore, singleUserAutoAcceptBaseline, checkpointStore, deploymentHooks, imageIndex, perTaskImage, sessionEnvSelection, liveQuestionFace, approverSeat, lockedKeys, } = ctx;
|
|
39
40
|
assertGuardPatternsUsable(config);
|
|
40
41
|
const onlySensitiveBaseline = buildOnlySensitiveBaselineWarning(config, { durableEnabled, singleUserAutoAcceptBaseline });
|
|
41
42
|
if (onlySensitiveBaseline)
|
|
42
43
|
logger.warn(onlySensitiveBaseline.event, onlySensitiveBaseline.fields);
|
|
43
|
-
const resolveSpec = async (body,
|
|
44
|
+
const resolveSpec = async (body, req, auth, opts) => {
|
|
44
45
|
assertRequestMcpUnlocked(body.mcpServers, lockedKeys);
|
|
45
46
|
if (opts?.leg === "fresh")
|
|
46
47
|
assertRequestMcpContentOrigin(body.mcpServers);
|
|
48
|
+
const rawMemoryCapture = body.memoryCapture;
|
|
49
|
+
if (rawMemoryCapture !== undefined && rawMemoryCapture !== "off") {
|
|
50
|
+
throw new HttpError(400, "memoryCapture must be the string 'off' when present (the session-level memory-capture opt-out declaration; absent = capture as usual — there is no 'on' spelling)", { code: "request.field_invalid" });
|
|
51
|
+
}
|
|
47
52
|
assertRequestA2aUnlocked(body.a2aPeers, lockedKeys);
|
|
48
53
|
const gated = await gateScenarioAndAppend(body, auth, opts);
|
|
49
54
|
const effMode = effectivePermissionMode(body, gated.parsedSettings.settings);
|
|
50
55
|
const lane = bindSettingsCwdEnvAndModel(body, auth, gated, effMode, opts);
|
|
51
56
|
const anchors = await resolveHistoryAnchors(body, auth);
|
|
52
|
-
const spec = assembleSpecLiteral(body, auth, opts, { ...gated, ...lane, ...anchors }, effMode);
|
|
57
|
+
const spec = assembleSpecLiteral(body, auth, req, opts, { ...gated, ...lane, ...anchors }, effMode);
|
|
53
58
|
const folded = await foldGovernanceAndSettings(body, auth, spec, gated, effMode);
|
|
54
59
|
const final = await applyImageFactsAndRouting(body, auth, folded.governed, {
|
|
55
60
|
scenarioName: gated.scenarioName,
|
|
@@ -116,17 +121,20 @@ export function createResolveSpec(ctx) {
|
|
|
116
121
|
};
|
|
117
122
|
const bindSettingsCwdEnvAndModel = (body, auth, gated, effMode, opts) => {
|
|
118
123
|
const { objective, parsedSettings } = gated;
|
|
124
|
+
const cwdWriteGate = cwdHonored(config) || deviceCwdHonored(config);
|
|
119
125
|
const execLane = config.remoteExec?.provider ?? "in-process";
|
|
126
|
+
if (auth?.sessionId)
|
|
127
|
+
fenceSessionOwner(auth.sessionId, auth.principal ?? null);
|
|
120
128
|
if (typeof body.cwd === "string" && body.cwd.length > 0 && auth?.sessionId) {
|
|
121
|
-
if (
|
|
129
|
+
if (cwdWriteGate && isValidCwd(body.cwd))
|
|
122
130
|
setSessionCwd(auth.sessionId, body.cwd);
|
|
123
131
|
else if (inProcessSingleUserLane(config) && isValidCwd(body.cwd) && satisfiedByProcessCwd(body.cwd, realpathSync))
|
|
124
132
|
logger.debug("task_cwd_inherited", { lane: execLane, sessionId: auth.sessionId });
|
|
125
133
|
else
|
|
126
|
-
logger.warn("task_cwd_ignored", { honored:
|
|
134
|
+
logger.warn("task_cwd_ignored", { honored: cwdWriteGate, lane: execLane, sessionId: auth.sessionId });
|
|
127
135
|
}
|
|
128
136
|
if (parsedSettings.settings?.shellEnv && auth?.sessionId) {
|
|
129
|
-
if (
|
|
137
|
+
if (cwdWriteGate)
|
|
130
138
|
setSessionShellEnv(auth.sessionId, parsedSettings.settings.shellEnv);
|
|
131
139
|
else if (inProcessSingleUserLane(config)) {
|
|
132
140
|
const requested = parsedSettings.settings.shellEnv;
|
|
@@ -204,28 +212,42 @@ export function createResolveSpec(ctx) {
|
|
|
204
212
|
let resumeAtEntryId;
|
|
205
213
|
if (typeof body.resumeAt === "string" && body.resumeAt.length > 0) {
|
|
206
214
|
if (!auth?.sessionId)
|
|
207
|
-
throw new HttpError(422, "resumeAt requires a session to branch (resume_at.no_session)");
|
|
215
|
+
throw new HttpError(422, "resumeAt requires a session to branch (resume_at.no_session)", { code: "resume_at.no_session" });
|
|
208
216
|
if (!resumeAnchorStore || !ownerAware.getLeafId)
|
|
209
217
|
throw new HttpError(501, "resume-at is not available on this worker (no session-store backend for the anchor map)");
|
|
210
218
|
resumeAtEntryId = await resumeAnchorStore.resolve(auth.sessionId, body.resumeAt, auth.principal ?? null);
|
|
211
219
|
if (resumeAtEntryId === undefined)
|
|
212
|
-
throw new HttpError(404, "resumeAt: no such message in this session (resume_at.unknown_event)");
|
|
220
|
+
throw new HttpError(404, "resumeAt: no such message in this session (resume_at.unknown_event)", { code: "resume_at.unknown_event" });
|
|
213
221
|
}
|
|
214
222
|
let rewindFilesToEntryId;
|
|
215
223
|
if (resumeAtEntryId === undefined && typeof body.rewindFilesTo === "string" && body.rewindFilesTo.length > 0) {
|
|
216
224
|
if (!auth?.sessionId)
|
|
217
|
-
throw new HttpError(422, "rewindFilesTo requires a session (rewind_files_to.no_session)");
|
|
225
|
+
throw new HttpError(422, "rewindFilesTo requires a session (rewind_files_to.no_session)", { code: "rewind_files_to.no_session" });
|
|
218
226
|
if (!resumeAnchorStore || !ownerAware.getLeafId)
|
|
219
227
|
throw new HttpError(501, "rewind-files-to is not available on this worker (no session-store backend for the anchor map)");
|
|
220
228
|
rewindFilesToEntryId = await resumeAnchorStore.resolve(auth.sessionId, body.rewindFilesTo, auth.principal ?? null);
|
|
221
229
|
if (rewindFilesToEntryId === undefined)
|
|
222
|
-
throw new HttpError(404, "rewindFilesTo: no such message in this session (rewind_files_to.unknown_event)");
|
|
230
|
+
throw new HttpError(404, "rewindFilesTo: no such message in this session (rewind_files_to.unknown_event)", { code: "rewind_files_to.unknown_event" });
|
|
223
231
|
}
|
|
224
232
|
const s4ProjectId = auth?.resolvedProjectId ?? (typeof body.projectId === "string" && body.projectId ? body.projectId.toLowerCase() : undefined);
|
|
225
233
|
const s4DefaultScopes = s4ProjectId ? config.projects[s4ProjectId]?.defaultScopes : undefined;
|
|
226
234
|
return { resumeAtEntryId, rewindFilesToEntryId, s4DefaultScopes };
|
|
227
235
|
};
|
|
228
|
-
const
|
|
236
|
+
const declaresInteractivePosture = (body, req, opts) => {
|
|
237
|
+
if (opts?.liveStream !== true)
|
|
238
|
+
return false;
|
|
239
|
+
if (body.verify === true || body.cascade === true)
|
|
240
|
+
return false;
|
|
241
|
+
if (liveQuestionFace === undefined)
|
|
242
|
+
return false;
|
|
243
|
+
if (body.interactiveTools === false)
|
|
244
|
+
return false;
|
|
245
|
+
if (headerStr(req?.headers["x-detach-on-disconnect"]) === "true")
|
|
246
|
+
return false;
|
|
247
|
+
const askForm = resolveAskSeamForm({}, approverSeat !== undefined ? { onAsk: approverSeat } : {});
|
|
248
|
+
return deriveAskEffective(askForm.form, "unresolved") === "human_reachable";
|
|
249
|
+
};
|
|
250
|
+
const assembleSpecLiteral = (body, auth, req, opts, parts, effMode) => {
|
|
229
251
|
const { scenarioName, cap, hands, centerDecls, acceptedAppend, parsedSettings, attachmentNotice, taskHooks, additionalDirectories, additionalReadDirectories, wireCatalog, picked, resumeAtEntryId, rewindFilesToEntryId, s4DefaultScopes, } = parts;
|
|
230
252
|
const spec = {
|
|
231
253
|
objective: attachmentNotice ? `${picked.cleanedObjective}\n\n${attachmentNotice}` : picked.cleanedObjective,
|
|
@@ -248,7 +270,9 @@ export function createResolveSpec(ctx) {
|
|
|
248
270
|
requireExistingSession: body.requireExistingSession === true ? true : undefined,
|
|
249
271
|
enableFork: enableForkFromBody(body, config, Boolean(centerRuntimeCapsResolver)),
|
|
250
272
|
suggestNextPrompts: normalizeSuggestNextPrompts(body.suggestNextPrompts),
|
|
251
|
-
|
|
273
|
+
restoreFiles: body.restoreFiles === true ? true : undefined,
|
|
274
|
+
acceptPartialRestore: body.acceptPartialRestore === true ? true : undefined,
|
|
275
|
+
...(body.rewindFiles === true ? { rewindFiles: true } : {}),
|
|
252
276
|
rewindFilesTo: rewindFilesToEntryId,
|
|
253
277
|
additionalDirectories,
|
|
254
278
|
additionalReadDirectories,
|
|
@@ -268,6 +292,7 @@ export function createResolveSpec(ctx) {
|
|
|
268
292
|
...(typeof body.interactiveTools === "boolean"
|
|
269
293
|
? { interactiveTools: body.interactiveTools }
|
|
270
294
|
: {}),
|
|
295
|
+
...(declaresInteractivePosture(body, req, opts) ? { interactionPosture: "interactive" } : {}),
|
|
271
296
|
...(typeof body.oneShot === "boolean" ? { oneShot: body.oneShot } : {}),
|
|
272
297
|
resilience: normalizeResilience(body.resilience, explicitOperatorOk(auth?.principal, config.operatorPrincipals)),
|
|
273
298
|
finalVerification: cap.finalVerification === true || body.finalVerification === true ? true : undefined,
|
|
@@ -334,7 +359,7 @@ export function createResolveSpec(ctx) {
|
|
|
334
359
|
return { ...(Object.keys(merged).length > 0 ? { limits: merged } : {}), ...(declarations.length > 0 ? { configOverrides: declarations } : {}) };
|
|
335
360
|
})(),
|
|
336
361
|
...(config.requirePrincipal !== true ? { backgroundScope: "session" } : {}),
|
|
337
|
-
memory: memoryEngine ? memorySpecForRequest(auth?.memoryScope, body.memoryWrite, s4DefaultScopes, { multiTenant: config.requirePrincipal === true }) : undefined,
|
|
362
|
+
memory: memoryEngine ? memorySpecForRequest(auth?.memoryScope, body.memoryWrite, s4DefaultScopes, { multiTenant: config.requirePrincipal === true }, body.memoryCapture) : undefined,
|
|
338
363
|
...((v) => (v !== undefined ? { memoryPersistenceCapable: v } : {}))(effectiveMemoryPersistenceCapable(config)),
|
|
339
364
|
tools: ((base) => {
|
|
340
365
|
const extra = [...(selectEnvTool ? [selectEnvTool] : []), ...(sendUserFileToolSpec ? [sendUserFileToolSpec] : [])];
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* ③ 模式分家(§4):`audit-only` 只调 `previewRetention` 记 `audit_only` 行,**一条破坏性方法都不调**;
|
|
22
22
|
* `enforce` 才调三方法。两支在代码里**物理分开**(不是同一段带 `if` 的调用序)—— 自审判据「grep 三个
|
|
23
23
|
* 方法名只出现在 enforce 臂」靠的就是这个形。
|
|
24
|
-
* ④ 单 domain 失败 ⇒ 记 `failed` 行 + **继续下一 domain**(
|
|
24
|
+
* ④ 单 domain 失败 ⇒ 记 `failed` 行 + **继续下一 domain**(一个坏租户不卡住整轮);同 domain 连败
|
|
25
25
|
* ≥ {@link RETENTION_SWEEP_STUCK_THRESHOLD} ⇒ `retention_sweep_stuck` 指标 + **一次性** warn。
|
|
26
26
|
*
|
|
27
27
|
* ── 破坏性审计行的属主(§6 F5)────────────────────────────────────────────────────────────────
|
|
@@ -181,7 +181,7 @@ export interface RetentionLaneCtx extends RetentionSweepCtx {
|
|
|
181
181
|
/**
|
|
182
182
|
* 起飞后的 lane 控制器(`create*` 形:有行为有状态)。
|
|
183
183
|
*
|
|
184
|
-
* 🔴 `stop()` 为什么必须**可等**(codex
|
|
184
|
+
* 🔴 `stop()` 为什么必须**可等**(codex 交叉复审 R1-[high],验真后加):`clearInterval` 只挡住**新** tick,
|
|
185
185
|
* 它不等当前这一轮。旧形的收尾链停表之后紧跟着就让租 ⇒ 新副本立刻接租,而旧副本还在删同一个域的
|
|
186
186
|
* 数据 —— 一个由**正常** SIGTERM/SIGINT 稳定触发的双执行者窗口(比任何竞态都好复现)。
|
|
187
187
|
* 正确的次序是:停表 → **等在飞那一轮落地** → 让租 → 关连接池。
|
|
@@ -29,10 +29,14 @@ import type { MemorySyncRunner } from "../memory-sync-client.js";
|
|
|
29
29
|
/**
|
|
30
30
|
* `RunnerDeps.onAsk` 的装配(#168 件4:从内联闭包提为具名导出,**纯 testability 重构、零行为变化**)。
|
|
31
31
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
32
|
+
* 为什么值得有名字(历史理由,#168 当时):bg / resume 两条腿彼时没有 per-task `spec.onAsk` 装配点,
|
|
33
|
+
* 它们唯一的审批接缝就是这一格。端到端测试此前只能把这一行**照抄**一份,再靠一条读源码
|
|
34
34
|
* 的正则当漂移告警 —— 那种锚只抓得到「这一行没了/改名了」,抓不到任何语义变化,而且抄件与真件从此是两
|
|
35
35
|
* 份实现。提成导出之后,测试直接取本函数,接缝与 production 是**同一个符号**。
|
|
36
|
+
* ⚠️ S-52 起**三腿都装** per-task `spec.onAsk = boundAsk`(sync=routes/tasks.ts、bg=runs.ts、
|
|
37
|
+
* resume=server.ts driveResumeLeg;core `resolveAsk` 取 `spec.onAsk ?? deps.onAsk` ⇒ 这三条腿及其继承链
|
|
38
|
+
* 子代不再落到本格)—— 本格现役的到达面 = 没有 per-task 装配的腿(headless/durable-submit、协调器在场
|
|
39
|
+
* 但 taskId 缺席的退化 resume 腿)与任何未来新腿的缺省兜底,fail-direction 不变(零 ctx ⇒ 政策口)。
|
|
36
40
|
*
|
|
37
41
|
* 命名(CLAUDE.md 工厂命名律):返回的是一个闭包(活对象)⇒ `create*`。
|
|
38
42
|
*
|
|
@@ -74,11 +78,11 @@ export interface RunnerDepsCtx {
|
|
|
74
78
|
memorySyncRunner: MemorySyncRunner | undefined;
|
|
75
79
|
/** design/170 件A(#148 件3③):org 记忆准入两 seam 的装配产物(boot/org-memory.ts)。进**共享
|
|
76
80
|
* 基座**——主/sub 两 Runner 必须同源:委托子代的 prepare 同样跑准入(委托冻结的重判腿),漏挂
|
|
77
|
-
* subRunner
|
|
81
|
+
* subRunner=子代平面跳过目录判决。 */
|
|
78
82
|
orgMemoryAdmission: import("./org-memory.js").OrgMemoryAdmissionWiring;
|
|
79
83
|
/** design/170 件B/C/D(#252 件1):三个部署治理座席的装配产物(boot/governance-seams.ts)。进**共享
|
|
80
84
|
* 基座** —— 合规否决与锁定层必须同样管住委托子代那条腿(子代 prepare 走同一套 preflight;漏挂
|
|
81
|
-
* subRunner =
|
|
85
|
+
* subRunner = 子代平面跳过档位与锁,与件A 同一个理由)。`retentionPolicy` 是纯声明,同源携带。 */
|
|
82
86
|
governanceSeams: import("./governance-seams.js").GovernanceSeams;
|
|
83
87
|
/** design/177 —— org 共享记忆库的供给面(core `RunnerDeps.sharedMemoryStores`)。在场即挂载
|
|
84
88
|
* `memory_list`/`memory_read` 两只工具(core 没有 TaskSpec 伴生旋钮:dep 的在场**就是**部署意图);
|
|
@@ -88,7 +92,13 @@ export interface RunnerDepsCtx {
|
|
|
88
92
|
toolResultStore: ToolResultStoreFull | undefined;
|
|
89
93
|
sessionPolicyStore: ReturnType<StoreBackend["sessionPolicy"]> | undefined;
|
|
90
94
|
runtimeCapsResolver: RunnerDeps["runtimeCapsResolver"];
|
|
91
|
-
|
|
95
|
+
/** S-15 per-edited-file rewind history (core `RunnerDeps.fileHistoryStore`; replaces the retired E19
|
|
96
|
+
* whole-tree snapshot seat — core 94632197 renamed the seat, not a coexistence). WIRING IS THE OPT-IN. */
|
|
97
|
+
fileHistoryStore: ReturnType<StoreBackend["fileHistory"]> | undefined;
|
|
98
|
+
/** S-1 legacy-epoch discriminant (core `RunnerDeps.legacyRewindBoundaryProbe`): lets the rewind refusal
|
|
99
|
+
* distinguish "never existed / reaped" from "exists in the RETIRED whole-tree epoch". Consulted only on
|
|
100
|
+
* the refusal path; diagnostic input, never a control input (a bad probe cannot change the outcome). */
|
|
101
|
+
legacyRewindBoundaryProbe: RunnerDeps["legacyRewindBoundaryProbe"];
|
|
92
102
|
/** #154 车二:持久化权限规则店 provider(core `RunnerDeps.permissionRuleStore`)。缺席 ⇒ 引擎的
|
|
93
103
|
* `permissionRules.storeWired` 如实报 false、`AskRequest.ruleOffers` 不铸(诚实缺席)。 */
|
|
94
104
|
permissionRuleStore: RunnerDeps["permissionRuleStore"];
|
|
@@ -126,7 +136,7 @@ export interface RunnerDepsCtx {
|
|
|
126
136
|
}
|
|
127
137
|
/** design/158 A10 留档发现②:main runner `RunnerDeps` 与 main.ts subRunner 字面量之间此前手工重复
|
|
128
138
|
* 的 ~15 个键,类型标注见 {@link createSharedRunnerDeps} 头注。 */
|
|
129
|
-
export type SharedRunnerDeps = Pick<RunnerDeps, "brain" | "readFace" | "readDenyPatterns" | "readDenyBuiltinTiers" | "readDenyBuiltinExclude" | "memoryDelegationEvidence" | "memoryProvenance" | "delegationEntryCaps" | "models" | "roles" | "tiers" | "pricing" | "tracer" | "promptSource" | "executionEnvFactory" | "lspManager" | "backgroundAgentStore" | "mailboxStore" | "rosterStore" | "hooks" | "toolResultStore" | "hands" | "sessionPolicyStore" | "usageWindows" | "usageWindowStore" | "memoryScopeAdmission" | "deploymentMemoryScopes" | "sharedMemoryStores" | "compliancePostureResolver" | "lockedConfig" | "retentionPolicy" | "onNotice" | "mcpRevocations">;
|
|
139
|
+
export type SharedRunnerDeps = Pick<RunnerDeps, "brain" | "readFace" | "readDenyPatterns" | "readDenyBuiltinTiers" | "readDenyBuiltinExclude" | "memoryDelegationEvidence" | "memoryProvenance" | "memoryCapturePolicy" | "delegationEntryCaps" | "models" | "roles" | "tiers" | "pricing" | "tracer" | "promptSource" | "executionEnvFactory" | "lspManager" | "backgroundAgentStore" | "mailboxStore" | "rosterStore" | "hooks" | "toolResultStore" | "hands" | "sessionPolicyStore" | "usageWindows" | "usageWindowStore" | "memoryScopeAdmission" | "deploymentMemoryScopes" | "sharedMemoryStores" | "compliancePostureResolver" | "lockedConfig" | "retentionPolicy" | "onNotice" | "mcpRevocations">;
|
|
130
140
|
/**
|
|
131
141
|
* design/158 A10 留档发现②(review 2026-07-29,[1543]§三族A 同源修补的延续):main runner 的
|
|
132
142
|
* `RunnerDeps` 字面量(下方 `createRunnerDeps`)与 `main.ts` 里 subRunner 的 `new Runner({...})`
|
|
@@ -194,7 +204,7 @@ export declare function createEngineNoticeForwarder(logger: {
|
|
|
194
204
|
}, router?: EngineNoticeRouter): NonNullable<RunnerDeps["onNotice"]>;
|
|
195
205
|
/**
|
|
196
206
|
* `onNotice` **席**的装配判据本身 —— 「`warn` 真在场才铸席」这一条从此是**一个可直接调用的函数**,
|
|
197
|
-
* 不是散在装配点、只能靠扫源码文本去猜的一行三元(codex
|
|
207
|
+
* 不是散在装配点、只能靠扫源码文本去猜的一行三元(codex 交叉复审 R1-[medium],验真后修)。
|
|
198
208
|
*
|
|
199
209
|
* 病(实测):把 leader 的门写成 `cfg.logger ? ((m, x) => cfg.logger?.warn?.(m, x)) : undefined` 时,
|
|
200
210
|
* 「装配点切片里出现过 `warn` 这个词」这类**源码文本**判据一律照绿 —— 而只装了 `info` 的部署会拿到一个
|
package/dist/boot/runner-deps.js
CHANGED
|
@@ -41,6 +41,7 @@ export function createSharedRunnerDeps(ctx) {
|
|
|
41
41
|
readDenyBuiltinExclude: ctx.config.readDenyBuiltinExclude ?? undefined,
|
|
42
42
|
memoryDelegationEvidence: ctx.config.memoryDelegationEvidence ?? undefined,
|
|
43
43
|
memoryProvenance: ctx.config.memoryProvenance ?? undefined,
|
|
44
|
+
memoryCapturePolicy: ctx.config.memoryCapturePolicy ?? undefined,
|
|
44
45
|
delegationEntryCaps: ctx.config.delegationEntryCaps ?? undefined,
|
|
45
46
|
executionEnvFactory: ctx.executionEnvFactory ? ctx.executionEnvFactory : undefined,
|
|
46
47
|
lspManager: ctx.lspManager ? ctx.lspManager : undefined,
|
|
@@ -64,7 +65,7 @@ export function createSharedRunnerDeps(ctx) {
|
|
|
64
65
|
return shared;
|
|
65
66
|
}
|
|
66
67
|
export function createRunnerDeps(ctx) {
|
|
67
|
-
const { config, logger, metrics, localRoot, outcomeSink, elicitation, question, toolApproval, sessionStore, memoryEngine, memorySyncRunner, runtimeCapsResolver,
|
|
68
|
+
const { config, logger, metrics, localRoot, outcomeSink, elicitation, question, toolApproval, sessionStore, memoryEngine, memorySyncRunner, runtimeCapsResolver, fileHistoryStore, legacyRewindBoundaryProbe, permissionRuleStore, fleetBus, workflowRunStore, workflowJournalStore, workflowAgentRegistry, workflowNotifyGate, workflowCompletionInbox, deliverWorkflowCompletion, getRunStore, } = ctx;
|
|
68
69
|
const sharedRunnerDeps = createSharedRunnerDeps(ctx);
|
|
69
70
|
const workflowModelAllowlist = workflowModelAllowlistFor(config);
|
|
70
71
|
const selfOrchestrationDeps = config.selfOrchestrationEnabled
|
|
@@ -160,7 +161,8 @@ export function createRunnerDeps(ctx) {
|
|
|
160
161
|
}
|
|
161
162
|
: undefined,
|
|
162
163
|
runtimeCapsResolver: runtimeCapsResolver ? runtimeCapsResolver : undefined,
|
|
163
|
-
|
|
164
|
+
fileHistoryStore: fileHistoryStore ? fileHistoryStore : undefined,
|
|
165
|
+
legacyRewindBoundaryProbe: legacyRewindBoundaryProbe ? legacyRewindBoundaryProbe : undefined,
|
|
164
166
|
permissionRuleStore: permissionRuleStore ? permissionRuleStore : undefined,
|
|
165
167
|
onBackgroundChildEvent: fleetBackgroundChildPublisher(fleetBus, (msg, fields) => logger.info(msg, fields)),
|
|
166
168
|
loadProjectMemory: config.requirePrincipal !== true && config.projectMemoryEnabled ? makeLoadProjectMemory({ logger }) : undefined,
|
|
@@ -9,10 +9,33 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { ServiceConfig } from "../config.js";
|
|
11
11
|
import type { Logger } from "../observability/logger.js";
|
|
12
|
+
import { type MemoryOptOutVerdictSource } from "../runtime-caps-resolver.js";
|
|
12
13
|
export interface RuntimeCapsCtx {
|
|
13
14
|
config: ServiceConfig;
|
|
14
15
|
logger: Logger;
|
|
16
|
+
/** design/383 S-2:`RuntimeCaps.allowMemoryOptOut` 的本地 verdict 源(`backend.memoryOptOutGrant()`;
|
|
17
|
+
* SQL 后端在场才有,local 车道 undefined)。缺席 ⇒ 本键不合成(零行为差)。 */
|
|
18
|
+
memoryOptOutGrant?: MemoryOptOutVerdictSource | undefined;
|
|
15
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* design/383 §3.1(S-49 S-1b)—— `MEMORY_CAPTURE_POLICY=governed` 的**半配置拒启**(`boot/memory-consolidation.ts`
|
|
22
|
+
* D1 / `boot/retention-lane.ts` 同姿态:安全/合规控件不得半开)。
|
|
23
|
+
*
|
|
24
|
+
* governed 的语义是「per-principal verdict **必答**」:core 对 verdict 缺席一律**拒跑**(fail-closed,部署显式
|
|
25
|
+
* 选的方向)。而 verdict 只能来自一个源 —— 本批唯一源 = SQL 后端上的 `memory_optout_grant` 表(三层折叠后
|
|
26
|
+
* 恒答显式 boolean)。governed 而无源 ⇒ 每一个 `capture:"off"` 声明都被 core 以
|
|
27
|
+
* `memory.capture_optout_denied` 拒掉,而运维看到的只是一台「启动成功、opt-out 全拒」的机器 —— 正是
|
|
28
|
+
* 「阀门开着而配不出来 ⇒ 悄悄读成别的」那一形。所以在**启动期**点名:要么接 SQL 后端(表随中央
|
|
29
|
+
* ensureSchema 建),要么改姿态。`open`/`capture-required`/缺席 不依赖源(前者故障放行、后者全拒,
|
|
30
|
+
* 都不问 verdict)。
|
|
31
|
+
*
|
|
32
|
+
* ⚠️ center 键 `EntitlementRuntimeCaps.allowMemoryOptOut` 是 settings-schema 的独立小件(S-50 §四 开放问题①),
|
|
33
|
+
* 到货前**不算源**;到货后本断言加一条「center 在场」析取臂即可,判据不变。
|
|
34
|
+
*/
|
|
35
|
+
export declare function assertMemoryCapturePolicyWirable(input: {
|
|
36
|
+
policy: ServiceConfig["memoryCapturePolicy"];
|
|
37
|
+
grantSourceWired: boolean;
|
|
38
|
+
}): void;
|
|
16
39
|
export declare function createRuntimeCaps(ctx: RuntimeCapsCtx): {
|
|
17
40
|
principalCaps: import("../runtime-caps-resolver.js").PrincipalEntitlementsClient | undefined;
|
|
18
41
|
centerRuntimeCapsResolver: ((principal: string | undefined) => Promise<import("@sema-agent/core").RuntimeCaps | undefined>) | undefined;
|
|
@@ -1,6 +1,21 @@
|
|
|
1
|
-
import { applyObserverEnvOptIn, centerEntitlementSourceWired, createPrincipalEntitlementsClient, scopedTokenNeedsWorker } from "../runtime-caps-resolver.js";
|
|
1
|
+
import { applyMemoryOptOutGrant, applyObserverEnvOptIn, centerEntitlementSourceWired, createPrincipalEntitlementsClient, scopedTokenNeedsWorker, } from "../runtime-caps-resolver.js";
|
|
2
|
+
export function assertMemoryCapturePolicyWirable(input) {
|
|
3
|
+
if (input.policy !== "governed")
|
|
4
|
+
return;
|
|
5
|
+
if (input.grantSourceWired)
|
|
6
|
+
return;
|
|
7
|
+
throw new Error(`MEMORY_CAPTURE_POLICY=governed requires a per-principal memory opt-out verdict source, and this deployment wires NONE ` +
|
|
8
|
+
`— under "governed" core REFUSES every session memory-capture opt-out whose verdict is absent (fail-closed, the posture's ` +
|
|
9
|
+
`own contract), so a governed worker without a source would refuse every \`memory.capture:"off"\` declaration and the ` +
|
|
10
|
+
`refusal would read as an entitlement denial rather than the misconfiguration it is. The only verdict source in this ` +
|
|
11
|
+
`version is the \`memory_optout_grant\` table on a SQL store backend (DB_BACKEND=mysql|pg; the table is created by the ` +
|
|
12
|
+
`central ensureSchema and administered through /v1/admin/memory-optout). Wire a SQL backend, or set ` +
|
|
13
|
+
`MEMORY_CAPTURE_POLICY=open (opt-outs take effect; only an explicit per-principal false denies) or ` +
|
|
14
|
+
`MEMORY_CAPTURE_POLICY=capture-required (every opt-out declaration refused, no source consulted).`);
|
|
15
|
+
}
|
|
2
16
|
export function createRuntimeCaps(ctx) {
|
|
3
17
|
const { config, logger } = ctx;
|
|
18
|
+
assertMemoryCapturePolicyWirable({ policy: config.memoryCapturePolicy, grantSourceWired: ctx.memoryOptOutGrant !== undefined });
|
|
4
19
|
if (config.configCenter && !config.configCenter.dryRun && scopedTokenNeedsWorker(config.configCenter.token, config.configCenter.worker)) {
|
|
5
20
|
logger.warn("runtime_caps_scoped_token_no_worker", {
|
|
6
21
|
reason: "SEMA_REGISTRY_TOKEN is a worker-scoped wpt_ token but SEMA_REGISTRY_WORKER is unset → center 403s per-principal caps → ALL workflow self-orchestration will be fail-closed denied. Set SEMA_REGISTRY_WORKER (the orchestrator normally injects it) or use the full SERVICE_PULL_TOKEN.",
|
|
@@ -15,11 +30,18 @@ export function createRuntimeCaps(ctx) {
|
|
|
15
30
|
})
|
|
16
31
|
: undefined;
|
|
17
32
|
const centerRuntimeCapsResolver = principalCaps?.resolveRuntimeCaps;
|
|
18
|
-
const
|
|
33
|
+
const withObservers = applyObserverEnvOptIn(centerRuntimeCapsResolver, {
|
|
19
34
|
experimentalObserverAgents: config.experimentalObserverAgents,
|
|
20
35
|
requirePrincipal: config.requirePrincipal,
|
|
21
36
|
warn: (msg, fields) => logger.warn(msg, fields),
|
|
22
37
|
});
|
|
38
|
+
const runtimeCapsResolver = applyMemoryOptOutGrant(withObservers, ctx.memoryOptOutGrant, {
|
|
39
|
+
onFault: (err, principal) => logger.warn("memory_optout_grant_resolve_failed", {
|
|
40
|
+
principal,
|
|
41
|
+
err: String(err),
|
|
42
|
+
effect: "allowMemoryOptOut left ABSENT for this resolve (never coined as false): open posture ⇒ the opt-out takes effect; governed ⇒ core refuses the run (verdict absent)",
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
23
45
|
return { principalCaps, centerRuntimeCapsResolver, runtimeCapsResolver };
|
|
24
46
|
}
|
|
25
47
|
//# sourceMappingURL=runtime-caps.js.map
|
|
@@ -6,6 +6,7 @@ import { PlanCacheProbe } from "../plan-cache-probe.js";
|
|
|
6
6
|
import type { CheckpointStoreFull, StoreBackend, ToolResultStoreFull } from "../plugins/store-backend.js";
|
|
7
7
|
import type { TaskAttachmentStore } from "../plugins/task-attachment-store.js";
|
|
8
8
|
import type { OwnerAwareSessionStore } from "../security.js";
|
|
9
|
+
import type { DeviceStore } from "../device-store.js";
|
|
9
10
|
import { SessionWatchRegistry } from "../session-watch.js";
|
|
10
11
|
import type { TaskListLane } from "./task-list-lane.js";
|
|
11
12
|
export interface SessionFacesCtx {
|
|
@@ -22,10 +23,14 @@ export interface SessionFacesCtx {
|
|
|
22
23
|
approvalExemptionStore: ReturnType<StoreBackend["approvalExemption"]> | undefined;
|
|
23
24
|
sessionPolicyStore: ReturnType<StoreBackend["sessionPolicy"]> | undefined;
|
|
24
25
|
taskAttachmentStore: TaskAttachmentStore | undefined;
|
|
25
|
-
|
|
26
|
+
fileHistoryStore: ReturnType<StoreBackend["fileHistory"]> | undefined;
|
|
26
27
|
workflowCompletionInbox: WorkflowCompletionInbox | undefined;
|
|
27
28
|
/** #318:会话级任务清单车道(E21 级联的一条腿)。缺席 = 装配未接本车道 ⇒ 无清单可删。 */
|
|
28
29
|
taskListLane: TaskListLane | undefined;
|
|
30
|
+
/** device lane 的四表店(E21 级联的一条腿:`device_session` 绑定行随会话删)。缺席 = 非 SQL 后端。 */
|
|
31
|
+
deviceStore: DeviceStore | undefined;
|
|
32
|
+
/** per-session cwd/shellEnv 登记簿的清除口(E21 级联的一条腿,codex R1-F1)。缺席 = 装配未接。 */
|
|
33
|
+
dropSessionScoped: ((sid: string) => void) | undefined;
|
|
29
34
|
}
|
|
30
35
|
export declare function createSessionFaces(ctx: SessionFacesCtx): {
|
|
31
36
|
ownerAware: OwnerAwareSessionStore;
|
|
@@ -6,7 +6,7 @@ import { setLeafAdvanceListener } from "../session-leaf-bus.js";
|
|
|
6
6
|
import { SessionWatchRegistry, posIntEnv } from "../session-watch.js";
|
|
7
7
|
import { defaultTaskRegistry } from "@sema-agent/core";
|
|
8
8
|
export function createSessionFaces(ctx) {
|
|
9
|
-
const { config, logger, metrics, localRoot, backend, sessionStore, runStore, checkpointStore, toolResultStore, resumeAnchorStore, approvalExemptionStore, sessionPolicyStore, taskAttachmentStore,
|
|
9
|
+
const { config, logger, metrics, localRoot, backend, sessionStore, runStore, checkpointStore, toolResultStore, resumeAnchorStore, approvalExemptionStore, sessionPolicyStore, taskAttachmentStore, fileHistoryStore, workflowCompletionInbox, taskListLane, deviceStore, dropSessionScoped, } = ctx;
|
|
10
10
|
const mysqlPool = backend?.mysqlPool();
|
|
11
11
|
const auditPgPool = backend?.pgPool();
|
|
12
12
|
const auditLocalRoot = backend?.kind === "local" ? (config.localDataRoot ?? localRoot) : undefined;
|
|
@@ -63,8 +63,22 @@ export function createSessionFaces(ctx) {
|
|
|
63
63
|
await taskAttachmentStore.deleteBySession(sessionId);
|
|
64
64
|
if (taskListLane)
|
|
65
65
|
await taskListLane.deleteBySession(sessionId);
|
|
66
|
-
if (
|
|
67
|
-
await
|
|
66
|
+
if (deviceStore)
|
|
67
|
+
await deviceStore.deleteByRootSession(sessionId);
|
|
68
|
+
dropSessionScoped?.(sessionId);
|
|
69
|
+
if (fileHistoryStore) {
|
|
70
|
+
if (typeof fileHistoryStore.deleteBySession === "function")
|
|
71
|
+
await fileHistoryStore.deleteBySession(sessionId);
|
|
72
|
+
else {
|
|
73
|
+
await fileHistoryStore.reap(sessionId, []);
|
|
74
|
+
logger.warn("session_file_history_baselines_retained", {
|
|
75
|
+
sessionId,
|
|
76
|
+
note: "the local file-history store has no whole-scope purge verb; boundaries were reaped but v1 baselines (original file bytes) remain under the data root until the upstream purge seam lands — recorded as an open deletion-rights gap, not silent",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (backend?.legacySnapshotPurge)
|
|
81
|
+
await backend.legacySnapshotPurge(sessionId);
|
|
68
82
|
if (workflowCompletionInbox)
|
|
69
83
|
await workflowCompletionInbox.purge(sessionId, owner ?? null).catch((err) => logger.warn("workflow_completion_inbox_purge_failed", { sessionId, err: String(err) }));
|
|
70
84
|
await purgeScratchpadDir(config.localDataRoot ?? localRoot, sessionId);
|
package/dist/boot/shutdown.d.ts
CHANGED
|
@@ -72,6 +72,14 @@ export interface ShutdownCtx {
|
|
|
72
72
|
storeLiveProbe: {
|
|
73
73
|
stop(): void;
|
|
74
74
|
} | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* device lane 的 WS 汇聚端(§8-R7 发版排空,车A-4)。缺席 = 本部署没有 device 车道。
|
|
77
|
+
*
|
|
78
|
+
* 🔴 排空联动**必须**由装配层驱动(`http/server.ts` 的 `deviceHub` 键头注逐字):§8-R7 的顺序
|
|
79
|
+
* (新提交 503 → 新 upgrade 拒 → 停发新指令 → 在途结果照收 → 才断连)是**部署编排**的语义,
|
|
80
|
+
* HTTP 层不能自作主张。所以 `drainState.draining` 翻真的那一刻,这里同步调 `beginDrain()`。
|
|
81
|
+
*/
|
|
82
|
+
deviceHub: import("../device-ws-hub.js").DeviceWsHub | undefined;
|
|
75
83
|
/** #131-2:config 60s 刷新环(config-center startRefreshLoop)——不停的话停机中途还可能热应用
|
|
76
84
|
* 一份新配置。缺席 = 纯 env 部署没起环。 */
|
|
77
85
|
configCenter: {
|
package/dist/boot/shutdown.js
CHANGED
|
@@ -5,7 +5,7 @@ import { createParentWatch } from "../parent-watch.js";
|
|
|
5
5
|
import { createEngineLeaseTracker } from "./engine-lease.js";
|
|
6
6
|
import { isScriptRealmRejection, describeRejectionReason } from "../orchestration/hardened-vm-runner.js";
|
|
7
7
|
export function installShutdownHandlers(ctx) {
|
|
8
|
-
const { config, logger, server, reaper, fleetReconcile, retentionLane, releaseRetentionLease, otelExporter, breakerState, costQuota, rateLimiter, runner, subRunner, lspManager, workflowNotifyJournal, fleetClient, backend, drainState, storeLiveProbe, configCenter, version, } = ctx;
|
|
8
|
+
const { config, logger, server, reaper, fleetReconcile, retentionLane, releaseRetentionLease, otelExporter, breakerState, costQuota, rateLimiter, runner, subRunner, lspManager, workflowNotifyJournal, fleetClient, backend, drainState, storeLiveProbe, configCenter, version, deviceHub, } = ctx;
|
|
9
9
|
const dataRoot = config.localDataRoot;
|
|
10
10
|
if (dataRoot) {
|
|
11
11
|
const prior = readCrashLast(dataRoot);
|
|
@@ -66,6 +66,7 @@ export function installShutdownHandlers(ctx) {
|
|
|
66
66
|
parentWatch?.stop();
|
|
67
67
|
engineLease?.stop();
|
|
68
68
|
storeLiveProbe?.stop();
|
|
69
|
+
void deviceHub?.close().catch((err) => logger.warn("device_hub_close_failed", { err: String(err) }));
|
|
69
70
|
configCenter?.stopRefreshLoop();
|
|
70
71
|
otelExporter?.stop();
|
|
71
72
|
breakerState?.stop();
|
|
@@ -107,6 +108,7 @@ export function installShutdownHandlers(ctx) {
|
|
|
107
108
|
}
|
|
108
109
|
draining = true;
|
|
109
110
|
drainState.draining = true;
|
|
111
|
+
deviceHub?.beginDrain();
|
|
110
112
|
drainState.since = Date.now();
|
|
111
113
|
void fleetClient?.announceNow();
|
|
112
114
|
const inflight = drainState.inflight?.() ?? 0;
|
package/dist/boot/stores.js
CHANGED
|
@@ -17,11 +17,13 @@ import { PgTaskAttachmentStore, TiDBTaskAttachmentStore, ensurePgTaskAttachmentS
|
|
|
17
17
|
import { createSessionStore } from "../plugins/session-store.js";
|
|
18
18
|
import { createTaskListLane } from "./task-list-lane.js";
|
|
19
19
|
import { ensurePgTaskListSchema, ensureTiDBTaskListSchema } from "../plugins/task-list-store-sql.js";
|
|
20
|
+
import { ensurePgDeviceSchema, ensureTiDBDeviceSchema } from "../plugins/device-store-sql.js";
|
|
20
21
|
import { assertCloudSnapshotBlobPosture, openStoreBackendWithFallback } from "../plugins/store-backend.js";
|
|
21
22
|
import { buildMemoryRemoteLaneWarn, memoryEngineBackendFor, memoryEngineRemoteLanePosture } from "../memory-scope.js";
|
|
22
23
|
import { assertToolResultProvenanceSchema } from "../plugins/tool-result-store-sql.js";
|
|
23
|
-
import { assertPermissionRuleApprovalSchema } from "../plugins/permission-rule-store-sql.js";
|
|
24
|
+
import { assertPermissionRuleApprovalSchema, assertPermissionRuleTicketSchema } from "../plugins/permission-rule-store-sql.js";
|
|
24
25
|
import { assertApprovalAskRuleMaterialSchema } from "../plugins/approval-ask-store-sql.js";
|
|
26
|
+
import { assertFileHistorySchema } from "../plugins/file-history-store-sql.js";
|
|
25
27
|
import { resolveStreamApprovalGate } from "../tool-approval.js";
|
|
26
28
|
import { buildMemoryWriteBoundaryAudit, effectiveMemoryPersistenceCapable } from "./memory-boundary.js";
|
|
27
29
|
import { buildMemoryPosture } from "../memory-posture.js";
|
|
@@ -55,6 +57,10 @@ export async function openStores(ctx) {
|
|
|
55
57
|
await assertPermissionRuleApprovalSchema(async (sql) => ({ rows: (await pgPool.query(sql)).rows }), "pg");
|
|
56
58
|
else if (mysqlPool)
|
|
57
59
|
await assertPermissionRuleApprovalSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "tidb");
|
|
60
|
+
if (pgPool)
|
|
61
|
+
await assertPermissionRuleTicketSchema(async (sql) => ({ rows: (await pgPool.query(sql)).rows }), "pg");
|
|
62
|
+
else if (mysqlPool)
|
|
63
|
+
await assertPermissionRuleTicketSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "tidb");
|
|
58
64
|
}
|
|
59
65
|
if (resolveStreamApprovalGate({
|
|
60
66
|
toolApprovalEnabled: config.toolApprovalEnabled === true,
|
|
@@ -67,6 +73,31 @@ export async function openStores(ctx) {
|
|
|
67
73
|
else if (mysqlPool)
|
|
68
74
|
await assertApprovalAskRuleMaterialSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "tidb");
|
|
69
75
|
}
|
|
76
|
+
if (pgPool)
|
|
77
|
+
await assertFileHistorySchema(async (sql) => ({ rows: (await pgPool.query(sql)).rows }), "pg");
|
|
78
|
+
else if (mysqlPool)
|
|
79
|
+
await assertFileHistorySchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "tidb");
|
|
80
|
+
{
|
|
81
|
+
const legacyProbeSql = "SELECT 1 FROM snapshot_manifest LIMIT 1";
|
|
82
|
+
const hasLegacyRows = await (pgPool
|
|
83
|
+
? pgPool.query(legacyProbeSql).then((r) => r.rows.length > 0)
|
|
84
|
+
: mysqlPool
|
|
85
|
+
? mysqlPool.query(legacyProbeSql).then(([rows]) => rows.length > 0)
|
|
86
|
+
: Promise.resolve(false)).catch(() => false);
|
|
87
|
+
if (hasLegacyRows) {
|
|
88
|
+
logger.warn("legacy_snapshot_epoch_rows_present", {
|
|
89
|
+
note: "rows from the RETIRED whole-tree snapshot epoch (snapshot_manifest/snapshot_blob) exist. They are NOT " +
|
|
90
|
+
"migrated (whole-tree manifests and per-file history are structurally different); rewind refusals for " +
|
|
91
|
+
"legacy-era boundaries name the retired epoch via the boundary probe; the retention lane keeps sweeping " +
|
|
92
|
+
"these rows by session, and the maintenance tick GCs their orphaned blob bytes.",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if ((process.env.REWIND_SNAPSHOT_MAX_MB ?? "") !== "") {
|
|
98
|
+
logger.warn("rewind_snapshot_max_mb_retired", {
|
|
99
|
+
note: "REWIND_SNAPSHOT_MAX_MB no longer has an effect: the whole-tree snapshot epoch is retired (S-15); per-edited-file history captures only files the agent touches, with no tree walk and no size gate. Remove the env var. Per-blob SQL sizing is governed by SNAPSHOT_BLOB_SQL_MAX_BYTES / object storage as before.",
|
|
100
|
+
});
|
|
70
101
|
}
|
|
71
102
|
{
|
|
72
103
|
const minioReq = ["MINIO_ENDPOINT", "MINIO_ACCESS_KEY", "MINIO_SECRET_KEY"];
|
|
@@ -343,6 +374,14 @@ export async function openStores(ctx) {
|
|
|
343
374
|
await ensureTiDBTaskListSchema(mysqlPool);
|
|
344
375
|
return createTaskListLane({ mysqlPool, pgPool, logger });
|
|
345
376
|
})();
|
|
377
|
+
{
|
|
378
|
+
const mysqlPool = backend?.mysqlPool?.();
|
|
379
|
+
const pgPool = backend?.pgPool?.();
|
|
380
|
+
if (pgPool)
|
|
381
|
+
await ensurePgDeviceSchema(async (text, params) => pgPool.query(text, params));
|
|
382
|
+
if (mysqlPool)
|
|
383
|
+
await ensureTiDBDeviceSchema(mysqlPool);
|
|
384
|
+
}
|
|
346
385
|
const sessionStore = createSessionStore(config, backend, metrics);
|
|
347
386
|
if (config.requirePrincipal && backend?.kind === "local") {
|
|
348
387
|
throw new Error("REQUIRE_PRINCIPAL=true is not supported on the local file backend (DB_BACKEND=local): session/run CONTENT is " +
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* 高水位(next_id)与插入序(next_sort)都由 meta 行的事务计数器持有,`mutate` 是真后端事务。
|
|
22
22
|
* - `memory`:无 SQL 后端(local/file 形、纯内存 dev)⇒ **进程级** per-session 内存店。跨 turn
|
|
23
23
|
* 存活(这就是 F2 的修点),但**跨进程重启丢失**,且 LRU 溢出(> `maxSessions`)时最老的会话
|
|
24
|
-
* 会被逐出=那条会话的待办清空。诚实登记在 USAGE(「local 形重启丢待办」)
|
|
24
|
+
* 会被逐出=那条会话的待办清空。诚实登记在 USAGE(「local 形重启丢待办」),不自造持久性:
|
|
25
25
|
* 这与 local 形其余会话态设施(perSessionCwd / TtlSessionStore)是同一姿势。
|
|
26
26
|
*
|
|
27
27
|
* ## 为什么 SQL 形也进同一只缓存
|
|
@@ -50,7 +50,7 @@ export interface TaskListLane {
|
|
|
50
50
|
* 🔴 为什么必须有:会话 id 由调用方自选、会话删除后可被**别人** `register` 重新登记(security.ts
|
|
51
51
|
* 的 claim-create),而本车道的 listKey 是 `sessionId` 的确定性派生 ⇒ 不级联的话,新化身第一次
|
|
52
52
|
* 打开清单就读到上一位主人的任务标题/描述,`TaskCreate` 还会从上一位的高水位续号(「这里以前
|
|
53
|
-
* 建过 47
|
|
53
|
+
* 建过 47 条」本身也是外泄)。同族腿(anchors / approval-exemption / session-policy / attachment /
|
|
54
54
|
* snapshot / scratchpad)全部走同一条级联,本条与它们同 scoping 理由:路由已在 DELETE 门证过会话
|
|
55
55
|
* 所有权,故按 sessionId 单键删。
|
|
56
56
|
*
|