@sema-agent/server 7.106.0 → 7.108.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 +52 -0
- package/README.md +2 -2
- package/USAGE.md +40 -4
- package/dist/approval-ask-audit-store.d.ts +62 -4
- package/dist/approval-ask-audit-store.js +67 -11
- package/dist/approval.js +16 -13
- package/dist/boot/coordinators.d.ts +4 -0
- package/dist/boot/coordinators.js +3 -2
- package/dist/boot/shutdown.d.ts +8 -0
- package/dist/boot/shutdown.js +31 -8
- package/dist/boot/stage-06-runners.d.ts +1 -0
- package/dist/boot/stage-06-runners.js +6 -3
- package/dist/boot/stage-07-capability-layer.d.ts +1 -0
- package/dist/boot/stage-08-reapers.d.ts +1 -0
- package/dist/boot/stage-09-leader.d.ts +1 -0
- package/dist/boot/stage-10-http-server.d.ts +1 -0
- package/dist/boot/stage-10-http-server.js +3 -1
- package/dist/brain.js +2 -1
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/config-catalog.d.ts +6 -1
- package/dist/config-catalog.js +34 -17
- package/dist/config-center/apply-effective.js +2 -0
- package/dist/config-center/types.d.ts +7 -0
- package/dist/deployment-governance.js +2 -1
- package/dist/fleet-client.d.ts +10 -2
- package/dist/fleet-client.js +14 -8
- package/dist/http/memory-compliance-failure-reply.d.ts +41 -0
- package/dist/http/memory-compliance-failure-reply.js +73 -0
- package/dist/http/memory-store-refusal-reply.d.ts +2 -2
- package/dist/http/resume-legs.js +3 -2
- package/dist/http/routes/capabilities.js +0 -2
- package/dist/http/routes/diagnostics.js +2 -0
- package/dist/http/routes/memory-compliance.js +2 -34
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/sessions.js +3 -11
- package/dist/http/routes/side-query.js +7 -2
- package/dist/http/routes/tasks.js +2 -1
- package/dist/memory-store-refusal.d.ts +2 -1
- package/dist/model-entry-headers.d.ts +41 -0
- package/dist/model-entry-headers.js +61 -0
- package/dist/model-entry-refusal.d.ts +6 -0
- package/dist/model-entry-refusal.js +4 -0
- package/dist/model-reach-scope.d.ts +55 -0
- package/dist/model-reach-scope.js +16 -0
- package/dist/model-unreachable-notice.d.ts +38 -0
- package/dist/model-unreachable-notice.js +72 -0
- package/dist/observability/fail-open.d.ts +4 -0
- package/dist/observability/fail-open.js +4 -0
- package/dist/observability/run-terminal.d.ts +8 -5
- package/dist/outbound-dispatcher.d.ts +69 -0
- package/dist/outbound-dispatcher.js +123 -3
- package/dist/plugins/park-commit-watch.d.ts +48 -0
- package/dist/plugins/park-commit-watch.js +87 -0
- package/dist/router/route-orchestration.js +7 -2
- package/dist/runs.js +3 -2
- package/dist/runtime-governance.js +3 -2
- package/dist/task-settings.d.ts +30 -17
- package/dist/task-settings.js +15 -4
- package/dist/tool-approval.d.ts +62 -0
- package/dist/tool-approval.js +67 -3
- package/dist/tool-rule-names.d.ts +25 -0
- package/dist/tool-rule-names.js +5 -0
- package/dist/trace/core-keyset-guard.d.ts +13 -1
- package/dist/trace/engine-notice-wire.d.ts +3 -1
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/project.d.ts +6 -3
- package/dist/trace/self-minted-wire.d.ts +71 -0
- package/dist/trace/self-minted-wire.js +28 -0
- package/package.json +2 -2
package/dist/boot/shutdown.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ import type { RateLimiter } from "../observability/rate-limit.js";
|
|
|
29
29
|
import type { startFleetClientFromEnv } from "../fleet-client.js";
|
|
30
30
|
import type { BreakerStateStore, CostQuotaStore, RateLimiterStore, StoreBackend } from "../plugins/store-backend.js";
|
|
31
31
|
import type { WorkflowNotifyJournalStore } from "../orchestration/workflow-notify-journal.js";
|
|
32
|
+
import type { ToolApprovalCoordinator } from "../tool-approval.js";
|
|
33
|
+
import type { ParkCommitWatch } from "../plugins/park-commit-watch.js";
|
|
32
34
|
export interface ShutdownCtx {
|
|
33
35
|
config: ServiceConfig;
|
|
34
36
|
/** [ref]①:崩溃遗言的 version 键(与 /v1/capabilities.version 同源=main 的 serviceVersion())。 */
|
|
@@ -87,6 +89,12 @@ export interface ShutdownCtx {
|
|
|
87
89
|
configCenter: {
|
|
88
90
|
stopRefreshLoop(): void;
|
|
89
91
|
} | undefined;
|
|
92
|
+
/** S-929:活体审批协调器(`TOOL_APPROVAL_ENABLED` 关 ⇒ 缺席)。hardShutdown 起点调它的 `drainForShutdown`:本进程握着的活卡
|
|
93
|
+
* 按断连同路收场、审计留有序关停记号 —— 否则下一次 boot 把有序重启读成崩溃(`crashed_before_park`)。 */
|
|
94
|
+
toolApproval: ToolApprovalCoordinator | undefined;
|
|
95
|
+
/** S-929 F1:checkpoint 店的 park 提交观察层(`plugins/park-commit-watch.ts`;在场 ⇔ 本部署有 checkpoint 店)。hardShutdown 在
|
|
96
|
+
* `backend.close()` 之前等它 quiesce —— 在飞的 `put`(审批 park / 资源挂起…,与审批协调器在不在场无关)不许被抽掉连接池。 */
|
|
97
|
+
parkCommits: ParkCommitWatch | undefined;
|
|
90
98
|
}
|
|
91
99
|
/**
|
|
92
100
|
* `installShutdownHandlers` 的**摘除把手**([ref] 二轮重扫件4)。
|
package/dist/boot/shutdown.js
CHANGED
|
@@ -6,8 +6,9 @@ import { installProcessExitBoundary } from "./exit-boundary.js";
|
|
|
6
6
|
import { createEngineLeaseTracker } from "./engine-lease.js";
|
|
7
7
|
import { writeExitLast, readExitLast, clearExitLast } from "./exit-last.js";
|
|
8
8
|
import { isScriptRealmRejection, describeRejectionReason } from "../orchestration/hardened-vm-runner.js";
|
|
9
|
+
const HARD_STOP_GRACE_MS = 10_000;
|
|
9
10
|
export function installShutdownHandlers(ctx) {
|
|
10
|
-
const { config, logger, server, reaper, fleetReconcile, retentionLane, releaseRetentionLease, otelExporter, breakerState, costQuota, rateLimiter, runner, subRunner, lspManager, workflowNotifyJournal, fleetClient, backend, drainState, storeLiveProbe, configCenter, version, deviceHub, } = ctx;
|
|
11
|
+
const { config, logger, server, reaper, fleetReconcile, retentionLane, releaseRetentionLease, otelExporter, breakerState, costQuota, rateLimiter, runner, subRunner, lspManager, workflowNotifyJournal, fleetClient, backend, drainState, storeLiveProbe, configCenter, version, deviceHub, toolApproval, parkCommits, } = ctx;
|
|
11
12
|
const dataRoot = config.localDataRoot;
|
|
12
13
|
if (dataRoot) {
|
|
13
14
|
const prior = readCrashLast(dataRoot);
|
|
@@ -69,6 +70,16 @@ export function installShutdownHandlers(ctx) {
|
|
|
69
70
|
closing = true;
|
|
70
71
|
if (dataRoot)
|
|
71
72
|
clearCrashLast(dataRoot);
|
|
73
|
+
const graceDeadlineMs = Date.now() + HARD_STOP_GRACE_MS;
|
|
74
|
+
const approvalDrain = toolApproval === undefined
|
|
75
|
+
? Promise.resolve()
|
|
76
|
+
: toolApproval
|
|
77
|
+
.drainForShutdown(graceDeadlineMs)
|
|
78
|
+
.then(({ uncommittedParks }) => {
|
|
79
|
+
for (const p of uncommittedParks)
|
|
80
|
+
logger.warn("approval_park_uncommitted_at_shutdown", { approvalId: p.approvalId, taskId: p.taskId });
|
|
81
|
+
})
|
|
82
|
+
.catch((err) => logger.warn("approval_drain_for_shutdown_failed", { err: String(err) }));
|
|
72
83
|
clearInterval(reaper);
|
|
73
84
|
clearInterval(fleetReconcile.timer);
|
|
74
85
|
const retentionTeardown = retentionLane === undefined
|
|
@@ -79,6 +90,7 @@ export function installShutdownHandlers(ctx) {
|
|
|
79
90
|
.then(() => undefined)
|
|
80
91
|
.catch(() => undefined);
|
|
81
92
|
fleetReconcile.reconciler.stop();
|
|
93
|
+
const routingStopped = fleetClient?.stopRouting() ?? Promise.resolve();
|
|
82
94
|
parentWatch?.stop();
|
|
83
95
|
engineLease?.stop();
|
|
84
96
|
storeLiveProbe?.stop();
|
|
@@ -86,23 +98,34 @@ export function installShutdownHandlers(ctx) {
|
|
|
86
98
|
configCenter?.stopRefreshLoop();
|
|
87
99
|
otelExporter?.stop();
|
|
88
100
|
breakerState?.stop();
|
|
89
|
-
if (costQuota && "stop" in costQuota)
|
|
90
|
-
costQuota.stop();
|
|
91
|
-
if (rateLimiter && "stop" in rateLimiter)
|
|
92
|
-
rateLimiter.stop();
|
|
93
101
|
runner.sessions.dispose();
|
|
94
102
|
subRunner.sessions.dispose();
|
|
95
103
|
void lspManager?.dispose?.();
|
|
96
104
|
void workflowNotifyJournal?.close?.();
|
|
97
105
|
exitBoundary.reapChildProcessesEarly();
|
|
98
|
-
|
|
106
|
+
const drained = approvalDrain
|
|
107
|
+
.then(() => parkCommits?.quiesce(graceDeadlineMs))
|
|
108
|
+
.then((q) => {
|
|
109
|
+
if (q !== undefined && q.inFlight > 0)
|
|
110
|
+
logger.warn("checkpoint_puts_inflight_at_backend_close", { inFlight: q.inFlight });
|
|
111
|
+
});
|
|
112
|
+
const ledgerStopped = drained.then(async () => {
|
|
113
|
+
if (costQuota && "stop" in costQuota)
|
|
114
|
+
costQuota.stop();
|
|
115
|
+
if (rateLimiter && "stop" in rateLimiter)
|
|
116
|
+
rateLimiter.stop();
|
|
117
|
+
await fleetClient?.flushFinalUsage();
|
|
118
|
+
});
|
|
99
119
|
server.close(() => {
|
|
100
|
-
void
|
|
120
|
+
void Promise.all([retentionTeardown, ledgerStopped])
|
|
121
|
+
.then(() => (backend ? backend.close() : Promise.resolve()))
|
|
122
|
+
.then(() => routingStopped)
|
|
123
|
+
.finally(() => process.exit(0));
|
|
101
124
|
});
|
|
102
125
|
const finalExit = setTimeout(() => { logger.warn("hard_shutdown_final_deadline", { afterMs: 15_000 }); process.exit(0); }, 15_000);
|
|
103
126
|
finalExit.unref?.();
|
|
104
127
|
server.closeIdleConnections?.();
|
|
105
|
-
const forceClose = setTimeout(() => server.closeAllConnections?.(),
|
|
128
|
+
const forceClose = setTimeout(() => server.closeAllConnections?.(), HARD_STOP_GRACE_MS);
|
|
106
129
|
forceClose.unref?.();
|
|
107
130
|
};
|
|
108
131
|
let draining = false;
|
|
@@ -14,6 +14,7 @@ export declare function runStage06(ctx: Awaited<ReturnType<typeof runStage05>>):
|
|
|
14
14
|
approvalExemptionStore: import("../plugins/approval-exemption-store.js").ApprovalExemptionStore | undefined;
|
|
15
15
|
centerRuntimeCapsResolver: ((principal: string | undefined) => Promise<import("@sema-agent/core").RuntimeCaps | undefined>) | undefined;
|
|
16
16
|
checkpointStore: import("../plugins/store-backend.js").CheckpointStoreFull | undefined;
|
|
17
|
+
parkCommits: import("../plugins/park-commit-watch.js").ParkCommitWatch | undefined;
|
|
17
18
|
durableEnabled: boolean;
|
|
18
19
|
elicitation: import("../elicitation.js").ElicitationCoordinator | undefined;
|
|
19
20
|
fleetBus: import("../fleet/fleet-bus.js").FleetEventBus;
|
|
@@ -13,6 +13,7 @@ import { buildConsolidationValveAudit, createMemoryConsolidationFaces, resolveCo
|
|
|
13
13
|
import { createPerModelAuthSeat } from "./side-query-lane.js";
|
|
14
14
|
import { createWorkflowOrchestration } from "./workflow-orchestration.js";
|
|
15
15
|
import { createLiveCoordinators } from "./coordinators.js";
|
|
16
|
+
import { createParkCommitWatch } from "../plugins/park-commit-watch.js";
|
|
16
17
|
import { createRuntimeCaps } from "./runtime-caps.js";
|
|
17
18
|
import { createRunnerDeps, createSharedRunnerDeps } from "./runner-deps.js";
|
|
18
19
|
import { createOrgMemoryAdmissionWiring } from "./org-memory.js";
|
|
@@ -22,8 +23,11 @@ import { parkedAskRedeem, runStore } from "./late-binds.js";
|
|
|
22
23
|
export function runStage06(ctx) {
|
|
23
24
|
const { backend, backgroundAgentStore, brain, sessionIncarnationOf, config, configCenter, consolidationValve, deploymentHooks, executionEnvFactory, fileHistoryStore, localRoot, logger, lspManager, mailboxRecipientLifecycle, mailboxStore, memoryEngine, memorySyncRunner, metrics, perSessionCwd, permissionRuleProvider, pricing, rosterStore, ruleConsent, sendUserFileTaskEnvs, sessionCaptureRecordStore, sessionCaptureRecords, sessionPolicyStore, sessionStore, taskAttachmentStore, taskListLane, toolResultStore, tracer, usageWindowStore } = ctx;
|
|
24
25
|
const { sqlWorkflowRunStore, workflowNotifyJournal, workflowCompletionInbox, deliverWorkflowCompletion, workflowNotifyGate, fleetBus, workflowRunStore, workflowJournalStore, outcomeSink, workflowRecoverOpts, workflowAgentRegistry, subagentSteerRegistry, workflowAgentSessionIndex, } = createWorkflowOrchestration({ config, logger, metrics, localRoot, backend, getRunStore: () => runStore });
|
|
26
|
+
const parkCommitted = backend?.checkpoint && config.durableApproval ? createParkCommitWatch(backend.checkpoint(logger)) : undefined;
|
|
27
|
+
const checkpointStore = parkCommitted?.store;
|
|
28
|
+
const parkCommits = parkCommitted?.watch;
|
|
25
29
|
const { elicitation, question, toolApproval, durableEnabled, streamApprovalGate, approvalAskAudit, approvalExemptionStore, sendUserFileEmitter, sendFileLedger, sendUserFileToolSpec } = createLiveCoordinators({
|
|
26
|
-
config, logger, backend, sendUserFileTaskEnvs, ruleConsent,
|
|
30
|
+
config, logger, backend, sendUserFileTaskEnvs, ruleConsent, parkCommits,
|
|
27
31
|
getParkedRedeem: () => parkedAskRedeem,
|
|
28
32
|
ruleScopeRootFor: (sessionId) => cardRuleScopeRoot(sessionId !== undefined ? perSessionCwd.get(sessionId) : undefined, config),
|
|
29
33
|
});
|
|
@@ -40,7 +44,6 @@ export function runStage06(ctx) {
|
|
|
40
44
|
logger.info("shared_memory_stores_enabled", { backend: backend?.kind });
|
|
41
45
|
const runnerOffloadStore = toolResultStore ?? new InMemoryToolResultStore({ maxTotalChars: 64_000_000 });
|
|
42
46
|
const commitHands = config.configProvider === "local" ? { commitCoAuthor: "Sema <noreply@vivi-ai.com>" } : undefined;
|
|
43
|
-
const checkpointStore = backend?.checkpoint && config.durableApproval ? backend.checkpoint(logger) : undefined;
|
|
44
47
|
const retentionExecutor = backend?.retention?.({ taskAttachmentTable: taskAttachmentStore !== undefined, taskListTables: taskListLane.backend !== "memory", logger });
|
|
45
48
|
const retentionLaneStore = backend?.retentionLane?.();
|
|
46
49
|
assertRetentionLaneWirable({
|
|
@@ -202,6 +205,6 @@ export function runStage06(ctx) {
|
|
|
202
205
|
};
|
|
203
206
|
const subRunner = new Runner(subRunnerDeps);
|
|
204
207
|
const handslessSubRunner = new Runner(withoutExecutionEnv(subRunnerDeps));
|
|
205
|
-
return { ...ctx, approvalAskAudit, approvalExemptionStore, centerRuntimeCapsResolver, checkpointStore, durableEnabled, elicitation, fleetBus, governanceSeams, handslessRunner, handslessSubRunner, hookAgent, hookAgentRunner, hookLlm, mcpRevocations, memoryConsolidationFaces, memoryOptOutGrantStore, orgMemoryAdmission, outcomeSink, principalCaps, question, retentionExecutor, retentionLaneStore, runner, runnerDeps, runtimeCapsPeekResolver, sendFileLedger, sendUserFileEmitter, sendUserFileToolSpec, sessionTitler, sharedMemoryStore, sqlWorkflowRunStore, streamApprovalGate, subRunner, subRunnerSessions, subagentSteerRegistry, toolApproval, workflowAgentRegistry, workflowAgentSessionIndex, workflowCompletionInbox, workflowJournalStore, workflowModelAllowlistSnapshot, workflowNotifyGate, workflowNotifyJournal, workflowRecoverOpts, workflowRunStore, workflowsCapable };
|
|
208
|
+
return { ...ctx, approvalAskAudit, approvalExemptionStore, centerRuntimeCapsResolver, checkpointStore, parkCommits, durableEnabled, elicitation, fleetBus, governanceSeams, handslessRunner, handslessSubRunner, hookAgent, hookAgentRunner, hookLlm, mcpRevocations, memoryConsolidationFaces, memoryOptOutGrantStore, orgMemoryAdmission, outcomeSink, principalCaps, question, retentionExecutor, retentionLaneStore, runner, runnerDeps, runtimeCapsPeekResolver, sendFileLedger, sendUserFileEmitter, sendUserFileToolSpec, sessionTitler, sharedMemoryStore, sqlWorkflowRunStore, streamApprovalGate, subRunner, subRunnerSessions, subagentSteerRegistry, toolApproval, workflowAgentRegistry, workflowAgentSessionIndex, workflowCompletionInbox, workflowJournalStore, workflowModelAllowlistSnapshot, workflowNotifyGate, workflowNotifyJournal, workflowRecoverOpts, workflowRunStore, workflowsCapable };
|
|
206
209
|
}
|
|
207
210
|
//# sourceMappingURL=stage-06-runners.js.map
|
|
@@ -27,6 +27,7 @@ export declare function runStage07(ctx: Awaited<ReturnType<typeof runStage06>>):
|
|
|
27
27
|
approvalAskAudit: import("../approval-ask-audit-store.js").FileApprovalAskAuditStore | undefined;
|
|
28
28
|
centerRuntimeCapsResolver: ((principal: string | undefined) => Promise<import("@sema-agent/core").RuntimeCaps | undefined>) | undefined;
|
|
29
29
|
checkpointStore: import("../plugins/store-backend.js").CheckpointStoreFull | undefined;
|
|
30
|
+
parkCommits: import("../plugins/park-commit-watch.js").ParkCommitWatch | undefined;
|
|
30
31
|
durableEnabled: boolean;
|
|
31
32
|
elicitation: import("../elicitation.js").ElicitationCoordinator | undefined;
|
|
32
33
|
fleetBus: import("../fleet/fleet-bus.js").FleetEventBus;
|
|
@@ -40,6 +40,7 @@ export declare function runStage08(ctx: Awaited<ReturnType<typeof runStage07>>):
|
|
|
40
40
|
approvalAskAudit: import("../approval-ask-audit-store.js").FileApprovalAskAuditStore | undefined;
|
|
41
41
|
centerRuntimeCapsResolver: ((principal: string | undefined) => Promise<import("@sema-agent/core").RuntimeCaps | undefined>) | undefined;
|
|
42
42
|
checkpointStore: import("../plugins/store-backend.js").CheckpointStoreFull | undefined;
|
|
43
|
+
parkCommits: import("../plugins/park-commit-watch.js").ParkCommitWatch | undefined;
|
|
43
44
|
durableEnabled: boolean;
|
|
44
45
|
elicitation: import("../elicitation.js").ElicitationCoordinator | undefined;
|
|
45
46
|
fleetBus: import("../fleet/fleet-bus.js").FleetEventBus;
|
|
@@ -76,6 +76,7 @@ export declare function runStage09(ctx: Awaited<ReturnType<typeof runStage08>>):
|
|
|
76
76
|
approvalAskAudit: import("../approval-ask-audit-store.js").FileApprovalAskAuditStore | undefined;
|
|
77
77
|
centerRuntimeCapsResolver: ((principal: string | undefined) => Promise<import("@sema-agent/core").RuntimeCaps | undefined>) | undefined;
|
|
78
78
|
checkpointStore: import("../plugins/store-backend.js").CheckpointStoreFull | undefined;
|
|
79
|
+
parkCommits: import("../plugins/park-commit-watch.js").ParkCommitWatch | undefined;
|
|
79
80
|
durableEnabled: boolean;
|
|
80
81
|
elicitation: import("../elicitation.js").ElicitationCoordinator | undefined;
|
|
81
82
|
fleetBus: import("../fleet/fleet-bus.js").FleetEventBus;
|
|
@@ -76,6 +76,7 @@ export declare function runStage10(ctx: Awaited<ReturnType<typeof runStage09>>):
|
|
|
76
76
|
approvalAskAudit: import("../approval-ask-audit-store.js").FileApprovalAskAuditStore | undefined;
|
|
77
77
|
centerRuntimeCapsResolver: ((principal: string | undefined) => Promise<import("@sema-agent/core").RuntimeCaps | undefined>) | undefined;
|
|
78
78
|
checkpointStore: import("../plugins/store-backend.js").CheckpointStoreFull | undefined;
|
|
79
|
+
parkCommits: import("../plugins/park-commit-watch.js").ParkCommitWatch | undefined;
|
|
79
80
|
durableEnabled: boolean;
|
|
80
81
|
elicitation: import("../elicitation.js").ElicitationCoordinator | undefined;
|
|
81
82
|
fleetBus: import("../fleet/fleet-bus.js").FleetEventBus;
|
|
@@ -26,7 +26,7 @@ import { bindServerLateSeats } from "./late-binds.js";
|
|
|
26
26
|
import { serviceVersion } from "../service-version.js";
|
|
27
27
|
import { buildDisplaySafeUrl } from "../trace/redact.js";
|
|
28
28
|
export async function runStage10(ctx) {
|
|
29
|
-
const { approvalAskAudit, approvalExemptionStore, approvalNonceStore, authorize, backend, backgroundAgentStore, brain, breakerState, centerRuntimeCapsResolver, checkpointStore, config, configCenter, consolidationValve, costQuota, deploymentHooks, deviceLane, drainState, durableEnabled, elicitation, fenceSessionOwner, noteSessionIncarnation, fileHistoryStore, fleetBus, fleetLease, fleetUsage, governanceSeams, handslessRunner, hookAgent, hookLlm, hookWakeBus, imageBakes, imageIndex, instanceId, instrumentDegenerate, leaderEndpoint, localRoot, logger, lspManager, mcpRevocations, memoryBundleFaces, memoryComplianceFaces, memoryConsolidationFaces, memoryEngine, memoryExportBackend, memoryOptOutGrantStore, memoryOriginFaces, memoryPosture, memorySyncCursors, metrics, modelUsageTracker, orgMemoryAdmission, otelExporter, outcomeSink, ownerAware, parkedReviveInheritedGate, parkedReviveSurface, perSessionCwd, perTaskImage, planCacheProbe, pricing, principalCaps, promptManifestTracker, purgeSession, question, rateLimiter, reaper, registryJwtVerifier, resumeAnchorStore, retentionLaneStarted, retentionLaneStore, ruleConsent, runStore, runner, runnerDeps, runtimeCapsPeekResolver, scenarioDetails, scenarios, selectEnvTool, sendFileLedger, sendUserFileEmitter, sendUserFileToolSpec, sessionAudit, sessionEnvSelection, sessionMemoryStatusFace, sessionPolicyStore, sessionTitler, sessionWatchRegistry, setSessionCwd, setSessionInheritEnv, setSessionShellEnv, sharedMemoryStore, sideQueryAccounting, sqlEngineFacts, sqlWorkflowRunStore, staticWiring, storePosture, subRunner, subagentSteerRegistry, taskAttachmentStore, taskLimitCaps, taskTimeoutSec, toolApproval, toolResultStore, usageWindowStore, webSearchProvider, workflowAgentRegistry, workflowAgentSessionIndex, workflowCompletionInbox, workflowJournalStore, workflowModelAllowlistSnapshot, workflowNotifyGate, workflowNotifyJournal, workflowRecoverOpts, workflowRunStore, workflowsCapable } = ctx;
|
|
29
|
+
const { approvalAskAudit, approvalExemptionStore, approvalNonceStore, authorize, backend, backgroundAgentStore, brain, breakerState, centerRuntimeCapsResolver, checkpointStore, parkCommits, config, configCenter, consolidationValve, costQuota, deploymentHooks, deviceLane, drainState, durableEnabled, elicitation, fenceSessionOwner, noteSessionIncarnation, fileHistoryStore, fleetBus, fleetLease, fleetUsage, governanceSeams, handslessRunner, hookAgent, hookLlm, hookWakeBus, imageBakes, imageIndex, instanceId, instrumentDegenerate, leaderEndpoint, localRoot, logger, lspManager, mcpRevocations, memoryBundleFaces, memoryComplianceFaces, memoryConsolidationFaces, memoryEngine, memoryExportBackend, memoryOptOutGrantStore, memoryOriginFaces, memoryPosture, memorySyncCursors, metrics, modelUsageTracker, orgMemoryAdmission, otelExporter, outcomeSink, ownerAware, parkedReviveInheritedGate, parkedReviveSurface, perSessionCwd, perTaskImage, planCacheProbe, pricing, principalCaps, promptManifestTracker, purgeSession, question, rateLimiter, reaper, registryJwtVerifier, resumeAnchorStore, retentionLaneStarted, retentionLaneStore, ruleConsent, runStore, runner, runnerDeps, runtimeCapsPeekResolver, scenarioDetails, scenarios, selectEnvTool, sendFileLedger, sendUserFileEmitter, sendUserFileToolSpec, sessionAudit, sessionEnvSelection, sessionMemoryStatusFace, sessionPolicyStore, sessionTitler, sessionWatchRegistry, setSessionCwd, setSessionInheritEnv, setSessionShellEnv, sharedMemoryStore, sideQueryAccounting, sqlEngineFacts, sqlWorkflowRunStore, staticWiring, storePosture, subRunner, subagentSteerRegistry, taskAttachmentStore, taskLimitCaps, taskTimeoutSec, toolApproval, toolResultStore, usageWindowStore, webSearchProvider, workflowAgentRegistry, workflowAgentSessionIndex, workflowCompletionInbox, workflowJournalStore, workflowModelAllowlistSnapshot, workflowNotifyGate, workflowNotifyJournal, workflowRecoverOpts, workflowRunStore, workflowsCapable } = ctx;
|
|
30
30
|
const stores = {
|
|
31
31
|
runStore,
|
|
32
32
|
resumeAnchorStore: resumeAnchorStore ? resumeAnchorStore : undefined,
|
|
@@ -303,6 +303,8 @@ export async function runStage10(ctx) {
|
|
|
303
303
|
version: serviceVersion(),
|
|
304
304
|
runner, subRunner, lspManager, workflowNotifyJournal, fleetClient, backend, drainState,
|
|
305
305
|
storeLiveProbe, configCenter,
|
|
306
|
+
toolApproval,
|
|
307
|
+
parkCommits,
|
|
306
308
|
deviceHub: deviceLane?.hub,
|
|
307
309
|
retentionLane: retentionLaneStarted,
|
|
308
310
|
releaseRetentionLease: retentionLaneStore !== undefined ? () => retentionLaneStore.release(instanceId) : undefined,
|
package/dist/brain.js
CHANGED
|
@@ -8,6 +8,7 @@ import { dispatchBrainLane } from "./model-provider.js";
|
|
|
8
8
|
import { openaiRouteBaseUrl } from "./model-route-endpoint.js";
|
|
9
9
|
import { catalogEntryFingerprint } from "./config-center/restart-signal.js";
|
|
10
10
|
import { buildDisplaySafeRefusal, buildDisplaySafeUrl } from "./trace/redact.js";
|
|
11
|
+
import { createModelReachBrain } from "./model-unreachable-notice.js";
|
|
11
12
|
function isOffDeploymentRoot(baseUrl, config) {
|
|
12
13
|
if (!baseUrl)
|
|
13
14
|
return false;
|
|
@@ -138,7 +139,7 @@ export function createBrain(config, deps = {}) {
|
|
|
138
139
|
});
|
|
139
140
|
}
|
|
140
141
|
}
|
|
141
|
-
return brain;
|
|
142
|
+
return createModelReachBrain(brain);
|
|
142
143
|
}
|
|
143
144
|
export function degradeTargetOf(config) {
|
|
144
145
|
return config.degrade?.reactive ? config.models?.[config.degrade.to] : undefined;
|
|
@@ -46,7 +46,7 @@ export declare const COMPOSITE_CAPABILITY_MEMBERS: {
|
|
|
46
46
|
readonly webSearch: readonly ["backend"];
|
|
47
47
|
readonly background: readonly ["listFace", "exitFaces"];
|
|
48
48
|
readonly taskSettings: readonly ["permissions", "permissionMode", "model", "outputStyle", "env", "hooks"];
|
|
49
|
-
readonly permissionModeAuto: readonly ["accepted", "classifierSeat", "entitlementSource", "
|
|
49
|
+
readonly permissionModeAuto: readonly ["accepted", "classifierSeat", "entitlementSource", "armed", "reason", "model"];
|
|
50
50
|
readonly writeProtection: readonly ["armed", "rows", "replaced"];
|
|
51
51
|
readonly executionLane: readonly ["provider", "toolsOnThisHost", "isolated"];
|
|
52
52
|
readonly retention: readonly ["mode", "maxAgeDays"];
|
|
@@ -7,7 +7,7 @@ export const COMPOSITE_CAPABILITY_MEMBERS = {
|
|
|
7
7
|
webSearch: ["backend"],
|
|
8
8
|
background: ["listFace", "exitFaces"],
|
|
9
9
|
taskSettings: ["permissions", "permissionMode", "model", "outputStyle", "env", "hooks"],
|
|
10
|
-
permissionModeAuto: ["accepted", "classifierSeat", "entitlementSource", "
|
|
10
|
+
permissionModeAuto: ["accepted", "classifierSeat", "entitlementSource", "armed", "reason", "model"],
|
|
11
11
|
writeProtection: ["armed", "rows", "replaced"],
|
|
12
12
|
executionLane: ["provider", "toolsOnThisHost", "isolated"],
|
|
13
13
|
retention: ["mode", "maxAgeDays"],
|
package/dist/config-catalog.d.ts
CHANGED
|
@@ -181,8 +181,13 @@ export declare const CONFIG_CATALOG: readonly ConfigCatalogSpec[];
|
|
|
181
181
|
* 进程起不来、每个 import 本模块的测试当场红)—— 不是 warn、不是标一个 `false` 位上 wire(7.105.0 及以前那只 `domainExists`
|
|
182
182
|
* 位就是后一种:它只看域不看路径,而 `models` 是真域,于是 `models.degrade` 这个不存在的成员被报成「中心可写」)。
|
|
183
183
|
*
|
|
184
|
-
* 解析只认 zod 的结构外衣(optional / nullable / default / effects / lazy)与对象 / 数组两种容器;认不出的节点 = 解析不出
|
|
184
|
+
* 解析只认 zod 的结构外衣(optional / nullable / default / catch / readonly / effects·管道 / lazy)与对象 / 数组两种容器;认不出的节点 = 解析不出
|
|
185
185
|
* (fail-closed:宁可多拒一个座位,也不放过一个假座位)。
|
|
186
|
+
*
|
|
187
|
+
* 🔴 S-909(7.106.0 合并复审 opus 腿 L-1):**只走 zod 公开面**。契约包今天是 zod 3.25、本仓是 zod 4 —— 读 zod 私有定义字段(类型判别名 /
|
|
188
|
+
* 内层 schema / lazy getter)的旧写法在契约包升 zod 4 那天会让 `models[].…` 整族座位解析不出,模块 import 期整只抛。两大版没有一个能同时
|
|
189
|
+
* 公开读到的「这是什么节点」判别位(v4 的 `.def.type` 在 v3 上不存在),`instanceof` 也跨不了两份 zod 的类身份 ⇒ 按两大版**同名的公开访问器**
|
|
190
|
+
* 认形,规则三条(见 {@link zodObjectShapeOf} / {@link isZodArrayFace} / {@link ZOD_WRAPPER_FACES})。钉:`test/config-catalog-zod-public-face.test.ts`。
|
|
186
191
|
*/
|
|
187
192
|
export declare function assertCenterSeatsResolvable(specs: readonly {
|
|
188
193
|
readonly name: string;
|
package/dist/config-catalog.js
CHANGED
|
@@ -498,24 +498,42 @@ export function assertCenterSeatsResolvable(specs) {
|
|
|
498
498
|
throw new Error(`config catalog claims center seats the settings-schema contract does not have — the center cannot publish them, so the catalog must not advertise a center write lane for them (delete the seat, or add the member to the contract first): ${bad.join("; ")}`);
|
|
499
499
|
}
|
|
500
500
|
}
|
|
501
|
-
function
|
|
501
|
+
function zodPublicMember(node, key) {
|
|
502
502
|
return typeof node === "object" && node !== null && key in node ? Reflect.get(node, key) : undefined;
|
|
503
503
|
}
|
|
504
|
+
function callZodPublic(node, key) {
|
|
505
|
+
const f = zodPublicMember(node, key);
|
|
506
|
+
return typeof f === "function" ? Reflect.apply(f, node, []) : undefined;
|
|
507
|
+
}
|
|
508
|
+
function zodObjectShapeOf(node) {
|
|
509
|
+
const shape = zodPublicMember(node, "shape");
|
|
510
|
+
return typeof shape === "object" && shape !== null ? shape : undefined;
|
|
511
|
+
}
|
|
512
|
+
function isZodArrayFace(node) {
|
|
513
|
+
return zodPublicMember(node, "element") !== undefined && typeof zodPublicMember(node, "length") === "function";
|
|
514
|
+
}
|
|
515
|
+
const ZOD_WRAPPER_FACES = [
|
|
516
|
+
(n) => callZodPublic(n, "unwrap"),
|
|
517
|
+
(n) => callZodPublic(n, "removeDefault"),
|
|
518
|
+
(n) => callZodPublic(n, "removeCatch"),
|
|
519
|
+
(n) => callZodPublic(n, "innerType"),
|
|
520
|
+
(n) => zodPublicMember(n, "schema"),
|
|
521
|
+
(n) => zodPublicMember(n, "in"),
|
|
522
|
+
];
|
|
504
523
|
function unwrapZodNode(node) {
|
|
505
524
|
let cur = node;
|
|
506
525
|
for (let depth = 0; depth < 32; depth++) {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
if (typeof getter === "function") {
|
|
515
|
-
cur = Reflect.apply(getter, def, []);
|
|
516
|
-
continue;
|
|
526
|
+
if (zodObjectShapeOf(cur) !== undefined || isZodArrayFace(cur))
|
|
527
|
+
return cur;
|
|
528
|
+
let inner;
|
|
529
|
+
for (const face of ZOD_WRAPPER_FACES) {
|
|
530
|
+
inner = face(cur);
|
|
531
|
+
if (inner !== undefined)
|
|
532
|
+
break;
|
|
517
533
|
}
|
|
518
|
-
|
|
534
|
+
if (inner === undefined)
|
|
535
|
+
return cur;
|
|
536
|
+
cur = inner;
|
|
519
537
|
}
|
|
520
538
|
return cur;
|
|
521
539
|
}
|
|
@@ -524,15 +542,14 @@ function zodPathResolves(schema, path) {
|
|
|
524
542
|
for (const segment of path.split(".")) {
|
|
525
543
|
const intoArray = segment.endsWith("[]");
|
|
526
544
|
const name = intoArray ? segment.slice(0, -2) : segment;
|
|
527
|
-
const shape =
|
|
528
|
-
if (
|
|
545
|
+
const shape = zodObjectShapeOf(cur);
|
|
546
|
+
if (shape === undefined || !Object.hasOwn(shape, name))
|
|
529
547
|
return false;
|
|
530
548
|
cur = unwrapZodNode(Reflect.get(shape, name));
|
|
531
549
|
if (intoArray) {
|
|
532
|
-
|
|
533
|
-
if (zodMember(def, "typeName") !== "ZodArray")
|
|
550
|
+
if (!isZodArrayFace(cur))
|
|
534
551
|
return false;
|
|
535
|
-
cur = unwrapZodNode(
|
|
552
|
+
cur = unwrapZodNode(zodPublicMember(cur, "element"));
|
|
536
553
|
}
|
|
537
554
|
}
|
|
538
555
|
return true;
|
|
@@ -2,6 +2,7 @@ import { resolveActiveTiers } from "@sema-agent/settings-schema";
|
|
|
2
2
|
import { modelKeyPoison } from "../key-resolver.js";
|
|
3
3
|
import { applyAutoCompactWindow, buildModelCostKey, findUnmatchableToolNames, formatUnmatchableToolNames, parseAutonomy } from "../config.js";
|
|
4
4
|
import { buildModelCompat, readModelCompat } from "../model-compat.js";
|
|
5
|
+
import { buildModelHeadersKey } from "../model-entry-headers.js";
|
|
5
6
|
import { validateCommandRules } from "../runtime-governance.js";
|
|
6
7
|
import { projectCollabToWorkflows, registerCollabWorkflows } from "../capabilities/collab-workflows.js";
|
|
7
8
|
import { stageLimits } from "./stage-limits.js";
|
|
@@ -50,6 +51,7 @@ function toModel(m, envDefaults = {}, logger) {
|
|
|
50
51
|
...(compat ? { compat } : {}),
|
|
51
52
|
...(m.extraBody ? { extraBody: m.extraBody } : {}),
|
|
52
53
|
...(Array.isArray(m.promptGuidance) && m.promptGuidance.length > 0 ? { promptGuidance: m.promptGuidance.map(String) } : {}),
|
|
54
|
+
...buildModelHeadersKey(m.name, m.headers, m.api),
|
|
53
55
|
};
|
|
54
56
|
const explicitAct = m.autoCompactTokens;
|
|
55
57
|
applyAutoCompactWindow(model, typeof explicitAct === "number" ? explicitAct : undefined);
|
|
@@ -82,6 +82,13 @@ export interface CenterModel {
|
|
|
82
82
|
* configured sentences parse fine in registry-core but never reach the assembly face ([ref]① 排雷:
|
|
83
83
|
* the missing leg made every promptGuidance pilot a false control). */
|
|
84
84
|
promptGuidance?: string[];
|
|
85
|
+
/**
|
|
86
|
+
* S-931(7.108.0)—— 这条条目发给供应商的**附加请求头**(部署 ↔ 供应商的契约;今天只有 `anthropic-beta`),上 core 的 per-model
|
|
87
|
+
* 头座 `Model.headers`。类型是 `unknown` 而不是那个结构,理由与 {@link CenterModel.compat} 逐字同:本类型是承载形,判据(闭集白名单 +
|
|
88
|
+
* 线路 + 值形)与坏形处置的单一属主是 `model-entry-headers.ts`(执法点 = S-704 逐条判据,判不过 ⇒ 条目不可用)。
|
|
89
|
+
* ⚠️ 两条读腿今天**剥掉**它(settings-schema 6.3.0 `ModelEntry` 无此键;候裁加字段):今天到得了这里的只有绕过读腿的输入。
|
|
90
|
+
*/
|
|
91
|
+
headers?: unknown;
|
|
85
92
|
enabled?: boolean;
|
|
86
93
|
}
|
|
87
94
|
export type CenterRoleTarget = {
|
|
@@ -2,12 +2,13 @@ import { join, posix } from "node:path";
|
|
|
2
2
|
import { FileError, StubExecutionEnv, combinePolicies, createAllowDenyPolicy, createDurableQuestionPolicy, createSensitivePathPolicy, createTranscriptIntegrityPolicy, err, isAbsoluteForFamily, isProtectedWrite, ok, pathTargetValue, protectivePathTargetOf, } from "@sema-agent/core";
|
|
3
3
|
import { createDurableAskPolicy, hasApprovalListIntent } from "./approval.js";
|
|
4
4
|
import { ASK_USER_QUESTION_TOOL_NAME } from "./approval-content-kind.js";
|
|
5
|
+
import { heldRuleName } from "./tool-rule-names.js";
|
|
5
6
|
export function createDurableQuestionGate(live) {
|
|
6
7
|
if (live === undefined)
|
|
7
8
|
return createDurableQuestionPolicy();
|
|
8
9
|
return {
|
|
9
10
|
check(req) {
|
|
10
|
-
if (req
|
|
11
|
+
if (heldRuleName(req, (n) => n === ASK_USER_QUESTION_TOOL_NAME) === undefined)
|
|
11
12
|
return { action: "allow" };
|
|
12
13
|
return live.hasLiveContext()
|
|
13
14
|
? { action: "allow" }
|
package/dist/fleet-client.d.ts
CHANGED
|
@@ -102,8 +102,16 @@ export interface FleetClient {
|
|
|
102
102
|
/** Immediate out-of-cycle announce — call when a self-reported input flips (draining: self-remove from routing FIRST;
|
|
103
103
|
* roster landed: become routable without waiting a heartbeat; restart signal changed: S-741). */
|
|
104
104
|
announceNow: () => Promise<void>;
|
|
105
|
-
/**
|
|
106
|
-
|
|
105
|
+
/**
|
|
106
|
+
* **路由面**停:停心跳、等在飞公告排空、best-effort DELETE 注销(各请求有界;从不抛)。之后的 `announceNow` 是空操作。
|
|
107
|
+
* 收尾链在 hardShutdown **起点**调(与 7.107.0 同序 —— 退出中的副本第一时间离开中心的路由表)。
|
|
108
|
+
*/
|
|
109
|
+
stopRouting: () => Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* **记账面**停:停用量窗定时器、上报最后一个(可能不满的)用量窗(有界;从不抛;空窗不发)。与路由面无关(不公告的引擎也报用量)。
|
|
112
|
+
* 收尾链排在**排空等待之后**调(S-929 F12:宽限窗里跑完的腿记下的用量必须进这一窗)。
|
|
113
|
+
*/
|
|
114
|
+
flushFinalUsage: () => Promise<void>;
|
|
107
115
|
}
|
|
108
116
|
/**
|
|
109
117
|
* Start the worker-side fleet loops. Caller has already gated on the center lane (startFleetClientFromEnv below).
|
package/dist/fleet-client.js
CHANGED
|
@@ -161,19 +161,16 @@ export function startFleetClient(opts) {
|
|
|
161
161
|
hb?.unref?.();
|
|
162
162
|
const uw = opts.usage ? setInterval(() => void flushUsage(), usageWindowMs) : undefined;
|
|
163
163
|
uw?.unref?.();
|
|
164
|
-
let
|
|
165
|
-
const
|
|
166
|
-
if (
|
|
164
|
+
let routingStopping = false;
|
|
165
|
+
const stopRouting = async () => {
|
|
166
|
+
if (routingStopping)
|
|
167
167
|
return;
|
|
168
|
-
|
|
168
|
+
routingStopping = true;
|
|
169
169
|
if (hb)
|
|
170
170
|
clearInterval(hb);
|
|
171
|
-
if (uw)
|
|
172
|
-
clearInterval(uw);
|
|
173
171
|
while (inFlight !== undefined)
|
|
174
172
|
await inFlight;
|
|
175
173
|
stopped = true;
|
|
176
|
-
await flushUsage();
|
|
177
174
|
if (!announcing)
|
|
178
175
|
return;
|
|
179
176
|
try {
|
|
@@ -182,7 +179,16 @@ export function startFleetClient(opts) {
|
|
|
182
179
|
catch {
|
|
183
180
|
}
|
|
184
181
|
};
|
|
185
|
-
|
|
182
|
+
let usageStopping = false;
|
|
183
|
+
const flushFinalUsage = async () => {
|
|
184
|
+
if (usageStopping)
|
|
185
|
+
return;
|
|
186
|
+
usageStopping = true;
|
|
187
|
+
if (uw)
|
|
188
|
+
clearInterval(uw);
|
|
189
|
+
await flushUsage();
|
|
190
|
+
};
|
|
191
|
+
return { announceNow, stopRouting, flushFinalUsage };
|
|
186
192
|
}
|
|
187
193
|
export function startFleetClientFromEnv(cfg, opts) {
|
|
188
194
|
const cc = cfg.configCenter;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S-930 —— 记忆合规面(抹除 / 出处)上 core **已分类拒**的**唯一** HTTP 映射。两面同调:
|
|
3
|
+
* · operator 面 `routes/memory-compliance.ts`(`POST /v1/memory/erase` · `GET /v1/memory/entries/:entryId/provenance`);
|
|
4
|
+
* · 会话所有者自助抹除面 `routes/sessions.ts`(`POST /v1/sessions/:id/memory/erase`)。
|
|
5
|
+
*
|
|
6
|
+
* ## 病(sdk 车 SH 黑盒实证,S-930)
|
|
7
|
+
* 修前自助面在路由里自写了一份更窄的分类:只认 `config.memory_erasure_request`(400)与 `memory.target_outside_store`(409),
|
|
8
|
+
* core 的另外三只 409 与 `ControlPlaneCorruptError` 全落 500 `internal.error` —— 「同一个 requestId 拿去抹另一个会话」这种**调用方自己
|
|
9
|
+
* 能改**的错被说成服务器坏了。两份分类 = 两个判官,少的那份恒是静默的一份。现在**码与状态**只在这里判一次,两面同读。
|
|
10
|
+
*
|
|
11
|
+
* ## 规则(三层,与 operator 面既有层序逐字同序)
|
|
12
|
+
* ① core 的**本口专属**码(闭集穷举 `switch`,见 {@link sentCoreCode})—— 码与状态两面同;文案按受众(下一节,一条规则);
|
|
13
|
+
* ② `memory.target_outside_store`(core 7.31.1 #1094 跨面 store 状态码)—— 409;
|
|
14
|
+
* ③ `ControlPlaneCorruptError` —— typed 500 `internal.memory_control_plane_corrupt`(fail-closed 信号,一码两义见下);
|
|
15
|
+
* 其余 ⇒ `false`(未分类,调用方发它自己那句 500 且**不回显**内部文本)。
|
|
16
|
+
*
|
|
17
|
+
* ## 文案按受众分(码与状态不分)—— **一条规则,三层同施,不按码挑**(F9,7.108.0 合并复审 opus 腿 O-9)
|
|
18
|
+
* core 原句是写给运维的诊断材料:② ③ 点名**宿主路径**(store 根、链解析到哪 / 控制面账本文件),① 的 `selector_mismatch` 带**首个请求的
|
|
19
|
+
* 选择子哈希**(`pinned set <selectHash>`,无盐 sha256 —— operator 选择子可字典还原,首个请求未必是这位会话所有者发的):
|
|
20
|
+
* · operator 受众 ⇒ 原句上 wire(过了 operator 门,这些材料对这个受众不是泄露);
|
|
21
|
+
* · 会话所有者受众 ⇒ **一律**一句固定指路(每码一句,只说「怎么办」),原句整句交 `withheld` 落运维 warn —— 不逐码判断哪句安全
|
|
22
|
+
* (逐码挑 = core 改一句文案就可能静默漏出一样新东西)。② ③ 的固定句**两形都真**:
|
|
23
|
+
* ② 链先于请求在场 ⇒ 提交点之前拒、什么都没做;提交点之后才换上的链 ⇒ 已删的几条算数、journal 留盘(codex 一审 C1);
|
|
24
|
+
* ③ 一码两义 —— 操作前账本读不出 ⇒ 什么都没发生;落定后残留枚举失败 ⇒ 抹除已提交、重放收敛(core 原话)。两句都不许诺零删除,
|
|
25
|
+
* 都指路「运维修好后用同一个 requestId 重发」(两义下这句都对)。本层**不**嗅 core 文案分辨前后(拿上游自由文本当判别式是第二真源)。
|
|
26
|
+
*/
|
|
27
|
+
import type { ServerResponse } from "node:http";
|
|
28
|
+
/**
|
|
29
|
+
* 已分类拒 → HTTP 状态的**唯一**码表 = 自铸 wire 值登记处的 `sessionMemoryEraseStatus` 集(F3:wire 变更清单从同一张表 diff,状态改一处、
|
|
30
|
+
* 清单跟着列)。两面同读(S-930:码与状态只判一次)。键写错 ⇒ tsc 红(索引的是 `as const` 表的键)。
|
|
31
|
+
*/
|
|
32
|
+
/** 读这张映射的受众(闭集)。会话所有者受众必须交一只 `withheld` —— 被换成固定句的 core 原句落到那里(运维材料不许丢)。 */
|
|
33
|
+
export type MemoryComplianceAudience = {
|
|
34
|
+
readonly kind: "operator";
|
|
35
|
+
} | {
|
|
36
|
+
readonly kind: "session_owner";
|
|
37
|
+
readonly withheld: (coreMessage: string) => void;
|
|
38
|
+
};
|
|
39
|
+
/** 按上面三层应答;返回 `true` = 已应答,`false` = 未分类(一个字节都没写,调用方发它自己那句 500 并落它自己的运维 warn)。 */
|
|
40
|
+
export declare function sentMemoryComplianceFailure(res: ServerResponse, err: unknown, audience: MemoryComplianceAudience): boolean;
|
|
41
|
+
//# sourceMappingURL=memory-compliance-failure-reply.d.ts.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { ControlPlaneCorruptError } from "@sema-agent/core";
|
|
2
|
+
import { targetOutsideStoreOf } from "../memory-store-refusal.js";
|
|
3
|
+
import { sentMemoryStoreRefusal } from "./memory-store-refusal-reply.js";
|
|
4
|
+
import { sendError } from "./send.js";
|
|
5
|
+
import { assertNever } from "./route-ctx.js";
|
|
6
|
+
function sentCoreCode(res, coreCode, coreMessage, audience) {
|
|
7
|
+
switch (coreCode) {
|
|
8
|
+
case "config.memory_erasure_request":
|
|
9
|
+
sendError(res, 400, "config.memory_erasure_request", textFor(audience, coreMessage, "session memory erasure refused — the erasure request is not valid; correct it and resend"));
|
|
10
|
+
return true;
|
|
11
|
+
case "memory.erasure_evidence_unavailable":
|
|
12
|
+
sendError(res, 409, "memory.erasure_evidence_unavailable", textFor(audience, coreMessage, "session memory erasure refused — this deployment's memory store cannot produce erasure evidence; resend with allowUnevidenced: true to erase without evidence, or ask the operator"));
|
|
13
|
+
return true;
|
|
14
|
+
case "memory.erasure_selector_mismatch":
|
|
15
|
+
sendError(res, 409, "memory.erasure_selector_mismatch", textFor(audience, coreMessage, "session memory erasure refused — this requestId already names a different erasure; resend with a new requestId"));
|
|
16
|
+
return true;
|
|
17
|
+
case "memory.erasure_census_incomplete":
|
|
18
|
+
sendError(res, 409, "memory.erasure_census_incomplete", textFor(audience, coreMessage, "session memory erasure refused — the memory store could not be read completely, so nothing was erased and nothing was recorded; ask the operator to repair it, then resend with the same requestId"));
|
|
19
|
+
return true;
|
|
20
|
+
default:
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function textFor(audience, coreMessage, ownerSentence) {
|
|
25
|
+
switch (audience.kind) {
|
|
26
|
+
case "operator":
|
|
27
|
+
return coreMessage;
|
|
28
|
+
case "session_owner":
|
|
29
|
+
audience.withheld(coreMessage);
|
|
30
|
+
return ownerSentence;
|
|
31
|
+
default:
|
|
32
|
+
return assertNever(audience);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function codeOf(err) {
|
|
36
|
+
if (!(err instanceof Error))
|
|
37
|
+
return undefined;
|
|
38
|
+
const { code } = err;
|
|
39
|
+
return typeof code === "string" ? code : undefined;
|
|
40
|
+
}
|
|
41
|
+
export function sentMemoryComplianceFailure(res, err, audience) {
|
|
42
|
+
const coreCode = codeOf(err);
|
|
43
|
+
if (coreCode !== undefined && sentCoreCode(res, coreCode, err instanceof Error ? err.message : String(err), audience))
|
|
44
|
+
return true;
|
|
45
|
+
const outside = targetOutsideStoreOf(err);
|
|
46
|
+
if (outside !== undefined) {
|
|
47
|
+
switch (audience.kind) {
|
|
48
|
+
case "operator":
|
|
49
|
+
return sentMemoryStoreRefusal(res, err);
|
|
50
|
+
case "session_owner":
|
|
51
|
+
audience.withheld(outside.message);
|
|
52
|
+
sendError(res, 409, "memory.target_outside_store", "session memory erasure refused — a directory in this deployment's memory store leads outside it (a link), so this erasure did not complete (a refusal before its commit point changed nothing; one after it keeps the deletions already made and a journal that finishes the rest once the link is removed); ask the operator to remove the link, then resend with the same requestId");
|
|
53
|
+
return true;
|
|
54
|
+
default:
|
|
55
|
+
return assertNever(audience);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (err instanceof ControlPlaneCorruptError) {
|
|
59
|
+
switch (audience.kind) {
|
|
60
|
+
case "operator":
|
|
61
|
+
sendError(res, 500, "internal.memory_control_plane_corrupt", err.message);
|
|
62
|
+
return true;
|
|
63
|
+
case "session_owner":
|
|
64
|
+
audience.withheld(err.message);
|
|
65
|
+
sendError(res, 500, "internal.memory_control_plane_corrupt", "session memory erasure could not be completed — this deployment's memory control plane could not be read cleanly (depending on where it stopped, either nothing was changed or the deletions were already committed and a replay finishes them); ask the operator to repair it, then resend with the same requestId");
|
|
66
|
+
return true;
|
|
67
|
+
default:
|
|
68
|
+
return assertNever(audience);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=memory-compliance-failure-reply.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* core 7.31.1 #1094 `memory.target_outside_store` 的 **operator 面 HTTP 映射** —— 唯一一处字面量(判据在
|
|
3
3
|
* `src/memory-store-refusal.ts`)。挂在每一个触 store 树的 operator 记忆口的已分类收尾上:
|
|
4
|
-
* `routes/memory-compliance.ts`(出处 /
|
|
4
|
+
* `routes/memory-compliance.ts`(出处 / 抹除;经 `http/memory-compliance-failure-reply.ts` 的 operator 受众臂)· `routes/memory-origin.ts`(外源列表 / 清标;**不含**只读控制面的清标账列表 ——
|
|
5
5
|
* core 的 wire 表逐字:只碰控制面的面不判,给它挂一条永远收不到的码路径正是附录 A 活触发门要防的形)·
|
|
6
|
-
* `routes/memory-bundle.ts`(导出 / 导入)。会话所有者的自助抹除口**不走这里**(`
|
|
6
|
+
* `routes/memory-bundle.ts`(导出 / 导入)。会话所有者的自助抹除口**不走这里**(S-930 起经 `http/memory-compliance-failure-reply.ts` 的会话所有者受众臂:同码、固定文案)。
|
|
7
7
|
* `POST /v1/admin/memory/consolidation/run` 也不走这里:那口把 core 的**任何**有码拒一律收成 409 `memory.consolidation_refused`
|
|
8
8
|
* (码进文案,附录 A 该行),本码已在那条臂上,不再给它第二个码。
|
|
9
9
|
*
|
package/dist/http/resume-legs.js
CHANGED
|
@@ -19,6 +19,7 @@ import { APPROVAL_GATE_KINDS, createApprovalCardEmitter, isApprovalGateKind, par
|
|
|
19
19
|
import { buildCheckpointAnchorHash } from "../approval-ask-audit-store.js";
|
|
20
20
|
import { TERMINAL_PARK_GATE_KINDS } from "../plugins/checkpoint-store-sql.js";
|
|
21
21
|
import { withPrincipal } from "../observability/principal-context.js";
|
|
22
|
+
import { withModelReachScope } from "../model-reach-scope.js";
|
|
22
23
|
import { modelTextEventData, turnEndEventData, contextUsageEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, workspaceChangedEventData, wiringManifestEventData, toolRosterDeltaEventData, toolDisclosureEventData, humanInputEventData, appendModelUsageDelta, appendPromptManifest, attachModelUsage } from "../trace/project.js";
|
|
23
24
|
import { redactSecrets } from "../trace/redact.js";
|
|
24
25
|
import { createLedgerSink, createSerialLedgerAppend } from "../trace/ledger-sink.js";
|
|
@@ -502,7 +503,7 @@ export function createResumeLegs(ctx) {
|
|
|
502
503
|
await args.onResumeCommitted();
|
|
503
504
|
let unregisterEngineNotice;
|
|
504
505
|
try {
|
|
505
|
-
result = await withPrincipal(principal, async () => {
|
|
506
|
+
result = await withModelReachScope(sessionId, () => withPrincipal(principal, async () => {
|
|
506
507
|
const resumeNotifiedKeys = new NotifiedKeys();
|
|
507
508
|
if (deps.runStore && taskId) {
|
|
508
509
|
const rs0 = deps.runStore;
|
|
@@ -871,7 +872,7 @@ export function createResumeLegs(ctx) {
|
|
|
871
872
|
return await (deps.sendUserFile && taskId
|
|
872
873
|
? deps.sendUserFile.runWithContext({ taskId, emit: async (frame) => { const { type, ...rest } = frame; await append(type, rest); } }, withElicitation)
|
|
873
874
|
: withElicitation());
|
|
874
|
-
});
|
|
875
|
+
}));
|
|
875
876
|
}
|
|
876
877
|
catch (e) {
|
|
877
878
|
if (e instanceof CheckpointError) {
|