@sema-agent/server 7.51.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/engine-lease.d.ts +1 -1
- package/dist/boot/execution-env.d.ts +1 -1
- 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 +12 -0
- package/dist/boot/resolve-spec.js +29 -7
- 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 +1 -1
- package/dist/boot/session-faces.js +14 -3
- package/dist/boot/stores.js +31 -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-types.d.ts +78 -18
- package/dist/config.js +45 -10
- package/dist/deployment-governance.d.ts +1 -1
- package/dist/device-enrollment.d.ts +2 -2
- package/dist/device-store.d.ts +3 -3
- package/dist/device-ws-protocol.d.ts +2 -2
- package/dist/env-facts.d.ts +1 -1
- package/dist/execution-lane-caps.d.ts +1 -1
- 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 +20 -9
- 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 +35 -13
- package/dist/http/server.js +105 -12
- 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/main.js +13 -6
- 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 +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/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 +1 -1
- package/dist/plugins/remote-env-k8s.d.ts +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 +59 -29
- package/dist/plugins/store-backend.js +75 -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 +1 -1
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-settings.d.ts +3 -3
- 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
package/dist/http/server.js
CHANGED
|
@@ -10,7 +10,7 @@ import { verifyDirectDoorProof } from "../principal-jwt.js";
|
|
|
10
10
|
import {} from "../memory-sync.js";
|
|
11
11
|
import { MAX_SETTINGS_OUTPUT_STYLE_CHARS, MAX_SETTINGS_PERMISSION_RULES, MAX_SETTINGS_ENV_VARS, MAX_SETTINGS_ENV_KEY_CHARS, MAX_SETTINGS_ENV_VALUE_CHARS } from "../task-settings.js";
|
|
12
12
|
import { parseHooksConfig } from "../hooks/hook-runner.js";
|
|
13
|
-
import { normalizeApproachNotice, validateTaskAgents } from "../spec-fields.js";
|
|
13
|
+
import { normalizeApproachNotice, unknownTaskAgentModelRef, validateTaskAgents } from "../spec-fields.js";
|
|
14
14
|
import { isValidCwd, MAX_ADDITIONAL_DIRS } from "../task-cwd.js";
|
|
15
15
|
import { runInBackground, evictIfConflict, stripCheckpointToken, parkToolCallId, TurnAnchorCapture, HEARTBEAT_MS, markChildrenStoppedByUserOnAbort } from "../runs.js";
|
|
16
16
|
import { readTurnActivityMs, recordTurnActivity } from "../turn-activity.js";
|
|
@@ -43,6 +43,7 @@ import { handleAdoption } from "./routes/adoption.js";
|
|
|
43
43
|
import { handleRetention } from "./routes/retention-ops.js";
|
|
44
44
|
import { handleAdminDrain } from "./routes/admin-drain.js";
|
|
45
45
|
import { handleAdminConfigRefresh } from "./routes/admin-config-refresh.js";
|
|
46
|
+
import { handleMemoryOptOut } from "./routes/admin-memory-optout.js";
|
|
46
47
|
import { handleMemoryPolicy } from "./routes/memory-policy.js";
|
|
47
48
|
import { handleMemoryBundle } from "./routes/memory-bundle.js";
|
|
48
49
|
import { handleMemoryCompliance } from "./routes/memory-compliance.js";
|
|
@@ -63,6 +64,7 @@ import { handleNotifyWake, SESSION_WAKE_RE } from "./routes/notify-wake.js";
|
|
|
63
64
|
import { handleApprovalsAssistant, streamApprovals, isQuestionAnswer, ASSISTANT_RESUME_RE, ASSISTANT_PLAN_REVIEW_RE } from "./routes/approvals-assistant.js";
|
|
64
65
|
export { streamApprovals, isQuestionAnswer };
|
|
65
66
|
import { handleRuns, handleRunVerbs, RUN_SUBAGENT_RESUME_RE } from "./routes/runs.js";
|
|
67
|
+
import { handleRunMemoryCapture } from "./routes/run-memory-capture.js";
|
|
66
68
|
import { handleSideQuery } from "./routes/side-query.js";
|
|
67
69
|
import { handleTasks } from "./routes/tasks.js";
|
|
68
70
|
import { handleLeader } from "./routes/leader.js";
|
|
@@ -136,6 +138,7 @@ const ROUTE_DOMAINS = [
|
|
|
136
138
|
handleA2a,
|
|
137
139
|
handleWorkflowAgentSteer,
|
|
138
140
|
handleRunVerbs,
|
|
141
|
+
handleRunMemoryCapture,
|
|
139
142
|
handleLeader,
|
|
140
143
|
handleImages,
|
|
141
144
|
handleApprovalsAssistant,
|
|
@@ -145,6 +148,7 @@ const ROUTE_DOMAINS = [
|
|
|
145
148
|
handleRetention,
|
|
146
149
|
handleAdminDrain,
|
|
147
150
|
handleAdminConfigRefresh,
|
|
151
|
+
handleMemoryOptOut,
|
|
148
152
|
handleMemoryPolicy,
|
|
149
153
|
handleMemoryBundle,
|
|
150
154
|
handleMemoryCompliance,
|
|
@@ -441,6 +445,8 @@ export function createHttpServer(rawDeps) {
|
|
|
441
445
|
return;
|
|
442
446
|
if (await handleRunVerbs(req, res, url, ctx))
|
|
443
447
|
return;
|
|
448
|
+
if (await handleRunMemoryCapture(req, res, url, ctx))
|
|
449
|
+
return;
|
|
444
450
|
if (await handleLeader(req, res, url, ctx))
|
|
445
451
|
return;
|
|
446
452
|
if (await handleImages(req, res, url, ctx))
|
|
@@ -459,6 +465,8 @@ export function createHttpServer(rawDeps) {
|
|
|
459
465
|
return;
|
|
460
466
|
if (await handleAdminConfigRefresh(req, res, url, ctx))
|
|
461
467
|
return;
|
|
468
|
+
if (await handleMemoryOptOut(req, res, url, ctx))
|
|
469
|
+
return;
|
|
462
470
|
if (await handleMemoryPolicy(req, res, url, ctx))
|
|
463
471
|
return;
|
|
464
472
|
if (await handleMemoryBundle(req, res, url, ctx))
|
|
@@ -490,7 +498,7 @@ export function createHttpServer(rawDeps) {
|
|
|
490
498
|
function runnerFor(spec) {
|
|
491
499
|
return deps.runnerFor?.(spec) ?? deps.runner;
|
|
492
500
|
}
|
|
493
|
-
async function prepareSpec(req, res, bodyIn, onTypedFailure) {
|
|
501
|
+
async function prepareSpec(req, res, bodyIn, onTypedFailure, legFacts) {
|
|
494
502
|
const body = bodyIn ?? (await readJson(req));
|
|
495
503
|
if (!body || typeof body.objective !== "string") {
|
|
496
504
|
sendError(res, 400, "request.field_invalid", "missing 'objective' string");
|
|
@@ -723,10 +731,22 @@ export function createHttpServer(rawDeps) {
|
|
|
723
731
|
sendError(res, 400, "request.field_invalid", "rewindFiles must be a boolean");
|
|
724
732
|
return null;
|
|
725
733
|
}
|
|
734
|
+
if (body.restoreFiles !== undefined && typeof body.restoreFiles !== "boolean") {
|
|
735
|
+
sendError(res, 400, "request.field_invalid", "restoreFiles must be a boolean");
|
|
736
|
+
return null;
|
|
737
|
+
}
|
|
738
|
+
if (body.acceptPartialRestore !== undefined && typeof body.acceptPartialRestore !== "boolean") {
|
|
739
|
+
sendError(res, 400, "request.field_invalid", "acceptPartialRestore must be a boolean");
|
|
740
|
+
return null;
|
|
741
|
+
}
|
|
726
742
|
if (body.memoryWrite !== undefined && typeof body.memoryWrite !== "boolean") {
|
|
727
743
|
sendError(res, 400, "request.field_invalid", "memoryWrite must be a boolean (false = pause memory writes for this run)");
|
|
728
744
|
return null;
|
|
729
745
|
}
|
|
746
|
+
if (body.memoryCapture !== undefined && body.memoryCapture !== "off") {
|
|
747
|
+
sendError(res, 400, "request.field_invalid", "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)");
|
|
748
|
+
return null;
|
|
749
|
+
}
|
|
730
750
|
if (body.requireExistingSession !== undefined && typeof body.requireExistingSession !== "boolean") {
|
|
731
751
|
sendError(res, 400, "request.field_invalid", "requireExistingSession must be a boolean");
|
|
732
752
|
return null;
|
|
@@ -808,6 +828,13 @@ export function createHttpServer(rawDeps) {
|
|
|
808
828
|
sendError(res, 400, "request.field_invalid", agentsErr);
|
|
809
829
|
return null;
|
|
810
830
|
}
|
|
831
|
+
const agentsBare = deps.config.models ?? {};
|
|
832
|
+
const agentsCatalog = expandTiers(agentsBare, deps.config.tiers ?? {}) ?? agentsBare;
|
|
833
|
+
const um = unknownTaskAgentModelRef(body.agents, agentsCatalog);
|
|
834
|
+
if (um !== undefined) {
|
|
835
|
+
sendError(res, 400, "request.unknown_reference", `unknown agents[${um.index}].model "${um.ref.slice(0, 120)}" — not in the configured catalog (a catalog name or tier word)`, { available: mentionableNames(deps.config, agentsCatalog) });
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
811
838
|
}
|
|
812
839
|
if (body.interactiveTools !== undefined && typeof body.interactiveTools !== "boolean") {
|
|
813
840
|
sendError(res, 400, "request.field_invalid", "interactiveTools must be a boolean");
|
|
@@ -932,7 +959,7 @@ export function createHttpServer(rawDeps) {
|
|
|
932
959
|
}
|
|
933
960
|
try {
|
|
934
961
|
const auth = deps.authorize ? await deps.authorize({ req, body }) : undefined;
|
|
935
|
-
const spec = await deps.resolveSpec(body, req, auth, { leg: "fresh" });
|
|
962
|
+
const spec = await deps.resolveSpec(body, req, auth, { leg: "fresh", ...(legFacts?.liveStream === true ? { liveStream: true } : {}) });
|
|
936
963
|
return { spec, runner: runnerFor(spec), auth, verify, cascade, jobId: body.jobId, body };
|
|
937
964
|
}
|
|
938
965
|
catch (err) {
|
|
@@ -948,21 +975,52 @@ export function createHttpServer(rawDeps) {
|
|
|
948
975
|
}
|
|
949
976
|
}
|
|
950
977
|
const resumeFleetScope = (req, auth) => req ? (gatedPrincipal(req, deps.config) ?? "default") : (auth.principal ?? "default");
|
|
951
|
-
async function resumeCheckpoint(sessionId, decision, reason, settledBy, req, answer, binding, onResumeCommitted, acceptEarly) {
|
|
978
|
+
async function resumeCheckpoint(sessionId, decision, reason, settledBy, req, answer, binding, onResumeCommitted, acceptEarly, decider) {
|
|
952
979
|
const cs = deps.checkpointStore;
|
|
953
980
|
const token = await cs.findPendingTokenBySession(sessionId);
|
|
954
981
|
if (binding?.checkpointToken && binding.checkpointToken !== token) {
|
|
955
|
-
|
|
982
|
+
let seenUnreadable = false;
|
|
983
|
+
const seen = await cs.get(binding.checkpointToken).catch((e) => {
|
|
984
|
+
seenUnreadable = true;
|
|
985
|
+
recordFailOpen("server.approvals.stale-echoed-token-unreadable", `session=${sessionId} err=${e instanceof Error ? e.message : String(e)}`);
|
|
986
|
+
return null;
|
|
987
|
+
});
|
|
956
988
|
const attributable = seen !== null && seen.sessionId === sessionId;
|
|
957
989
|
if (!attributable && seen !== null) {
|
|
958
990
|
deps.logger?.warn?.("approval_stale_token_foreign", { sessionId, tokenSession: seen.sessionId ?? null });
|
|
959
991
|
}
|
|
992
|
+
if (!token && !attributable && !seenUnreadable) {
|
|
993
|
+
deps.logger?.info?.("approval_decide_no_pending", { sessionId, staleTokenEchoed: true });
|
|
994
|
+
return { status: 404, body: { error: "approval not found", errorCode: "not_found.approval" } };
|
|
995
|
+
}
|
|
996
|
+
let currentPending;
|
|
997
|
+
if (token && decider !== undefined) {
|
|
998
|
+
const cur = await cs.get(token).catch((e) => {
|
|
999
|
+
recordFailOpen("server.approvals.stale-current-pending-unreadable", `session=${sessionId} err=${e instanceof Error ? e.message : String(e)}`);
|
|
1000
|
+
return null;
|
|
1001
|
+
});
|
|
1002
|
+
const curPa = cur?.pendingAction;
|
|
1003
|
+
const curOwner = cur ? decodeCheckpointScope(cur.scope) : undefined;
|
|
1004
|
+
const scopeOk = cur !== null && (decider.explicitOperator || curOwner === undefined || curOwner === decider.principal);
|
|
1005
|
+
if (cur && cur.sessionId === sessionId && !scopeOk) {
|
|
1006
|
+
deps.logger?.info?.("approval_decide_no_pending", { sessionId, staleTokenEchoed: true, foreignCurrentSuppressed: true });
|
|
1007
|
+
return { status: 404, body: { error: "approval not found", errorCode: "not_found.approval" } };
|
|
1008
|
+
}
|
|
1009
|
+
if (cur && cur.status === "pending" && cur.sessionId === sessionId && scopeOk && curPa?.kind === "tool_approval" && curPa.toolCallId) {
|
|
1010
|
+
currentPending = {
|
|
1011
|
+
toolName: curPa.toolName,
|
|
1012
|
+
boundCallId: curPa.toolCallId,
|
|
1013
|
+
...(curPa.boundInputHash ? { boundInputHash: curPa.boundInputHash } : {}),
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
960
1017
|
return {
|
|
961
1018
|
status: 409,
|
|
962
1019
|
body: {
|
|
963
1020
|
error: "the approval you are deciding is no longer current (already resolved or superseded since you viewed it)",
|
|
964
1021
|
errorCode: "approval_stale",
|
|
965
1022
|
...(attributable ? { terminal: "resolved" } : {}),
|
|
1023
|
+
...(currentPending ? { currentPending } : {}),
|
|
966
1024
|
},
|
|
967
1025
|
};
|
|
968
1026
|
}
|
|
@@ -982,6 +1040,13 @@ export function createHttpServer(rawDeps) {
|
|
|
982
1040
|
}
|
|
983
1041
|
if (!cp)
|
|
984
1042
|
return { status: 404, body: { error: "checkpoint not found", errorCode: "not_found.checkpoint" } };
|
|
1043
|
+
if (decider !== undefined && !decider.explicitOperator) {
|
|
1044
|
+
const cpOwner = decodeCheckpointScope(cp.scope);
|
|
1045
|
+
if (cpOwner !== undefined && cpOwner !== decider.principal) {
|
|
1046
|
+
deps.logger?.warn?.("approval_decide_row_scope_mismatch", { sessionId, note: "loaded pending row is foreign to the verified caller — TOCTOU fold" });
|
|
1047
|
+
return { status: 404, body: { error: "approval not found", errorCode: "not_found.approval" } };
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
985
1050
|
const decideGateKind = cp.gate?.kind;
|
|
986
1051
|
if (!isApprovalGateKind(decideGateKind)) {
|
|
987
1052
|
const activeForPath = decideGateKind
|
|
@@ -1009,6 +1074,13 @@ export function createHttpServer(rawDeps) {
|
|
|
1009
1074
|
},
|
|
1010
1075
|
};
|
|
1011
1076
|
}
|
|
1077
|
+
const paForGrant = cp.pendingAction.kind === "tool_approval" ? cp.pendingAction : undefined;
|
|
1078
|
+
const loadedGrantTool = paForGrant !== undefined && paForGrant.toolName && paForGrant.toolName !== "AskUserQuestion"
|
|
1079
|
+
? paForGrant.toolName
|
|
1080
|
+
: null;
|
|
1081
|
+
const boundGrant = onResumeCommitted
|
|
1082
|
+
? (overrideSessionId) => onResumeCommitted({ ...(overrideSessionId !== undefined ? { overrideSessionId } : {}), validatedToolName: loadedGrantTool })
|
|
1083
|
+
: undefined;
|
|
1012
1084
|
if (req !== undefined && deps.backgroundAgentStore !== undefined && deps.parkedReviveTool !== undefined) {
|
|
1013
1085
|
const parked = await decideParkedAgent({
|
|
1014
1086
|
agentStore: deps.backgroundAgentStore,
|
|
@@ -1022,7 +1094,7 @@ export function createHttpServer(rawDeps) {
|
|
|
1022
1094
|
token, scope: cp.scope, sessionId: cp.sessionId, pendingAction: cp.pendingAction,
|
|
1023
1095
|
decision, settledBy, ...(reason !== undefined ? { reason } : {}),
|
|
1024
1096
|
...(binding !== undefined ? { binding: { ...(binding.boundCallId !== undefined ? { boundCallId: binding.boundCallId } : {}), ...(binding.boundInputHash !== undefined ? { boundInputHash: binding.boundInputHash } : {}), ...(binding.updatedInput !== undefined ? { updatedInput: binding.updatedInput } : {}) } } : {}),
|
|
1025
|
-
...(
|
|
1097
|
+
...(boundGrant ? { grantRemember: (rootSessionId) => boundGrant(rootSessionId) } : {}),
|
|
1026
1098
|
...(answer !== undefined ? { answer } : {}),
|
|
1027
1099
|
});
|
|
1028
1100
|
if (parked !== undefined) {
|
|
@@ -1091,7 +1163,7 @@ export function createHttpServer(rawDeps) {
|
|
|
1091
1163
|
settledBy,
|
|
1092
1164
|
};
|
|
1093
1165
|
const verifyRounds = verifyRoundsFromBody(ctx.body);
|
|
1094
|
-
return driveResumeIntoRunLog({ runner: runnerFor(spec), token, sessionId: cp.sessionId, principal: auth.principal, fleetScope: resumeFleetScope(req, auth), taskConfig, resumeObjective, outcome, verifyRounds, ...(
|
|
1166
|
+
return driveResumeIntoRunLog({ runner: runnerFor(spec), token, sessionId: cp.sessionId, principal: auth.principal, fleetScope: resumeFleetScope(req, auth), taskConfig, resumeObjective, outcome, verifyRounds, ...(boundGrant ? { onResumeCommitted: boundGrant } : {}), ...(acceptEarly === true ? { acceptEarly: true } : {}) });
|
|
1095
1167
|
}
|
|
1096
1168
|
async function driveResumeIntoRunLog(args) {
|
|
1097
1169
|
if (args.acceptEarly !== true)
|
|
@@ -1158,6 +1230,17 @@ export function createHttpServer(rawDeps) {
|
|
|
1158
1230
|
? fleetRunPublisher(deps.fleetBus, { runId: taskId, scope: fleetScope, rootTaskId: taskId, ...fleetRunLabels(resumeObjective) })
|
|
1159
1231
|
: undefined;
|
|
1160
1232
|
const resumeTaskConfig = taskId ? { ...taskConfig, taskId } : taskConfig;
|
|
1233
|
+
if (deps.toolApproval && taskId) {
|
|
1234
|
+
const toolApproval = deps.toolApproval;
|
|
1235
|
+
resumeTaskConfig.onAsk = approvalLeg.windowZero
|
|
1236
|
+
? () => Promise.resolve(toolApproval.unattendedAskOutcome())
|
|
1237
|
+
: toolApproval.boundAsk({
|
|
1238
|
+
owner: principal ?? null,
|
|
1239
|
+
taskId,
|
|
1240
|
+
sessionId,
|
|
1241
|
+
...(approvalLeg.active ? { legKey, ...(legDeadlineMonotonic !== undefined ? { legDeadlineMonotonic } : {}) } : {}),
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1161
1244
|
if (taskId && resumeTaskConfig.resourceSuspend)
|
|
1162
1245
|
recordResumeResourceWindow(taskId, resumeTaskConfig.resourceSuspend);
|
|
1163
1246
|
let fleetSettled = false;
|
|
@@ -1189,7 +1272,7 @@ export function createHttpServer(rawDeps) {
|
|
|
1189
1272
|
const cancelCtrl = new AbortController();
|
|
1190
1273
|
const preemptCtrl = new AbortController();
|
|
1191
1274
|
if (taskId && deps.runStore) {
|
|
1192
|
-
claimedRow = freshRunClaimed ? true : await deps.runStore.markResuming(taskId);
|
|
1275
|
+
claimedRow = freshRunClaimed ? true : await deps.runStore.markResuming(taskId, deps.instanceId ?? "default");
|
|
1193
1276
|
if (!claimedRow)
|
|
1194
1277
|
return { status: 409, body: { error: "run is not in a resumable (suspended) state (already resumed, decided, or expired)", errorCode: "conflict.not_resumable" } };
|
|
1195
1278
|
markChildrenStoppedByUserOnAbort(cancelCtrl.signal, taskId, principal);
|
|
@@ -2118,7 +2201,7 @@ export function createHttpServer(rawDeps) {
|
|
|
2118
2201
|
...(req.gateBoundInputHash !== null ? { boundInputHash: req.gateBoundInputHash } : {}),
|
|
2119
2202
|
...(req.updatedInput !== undefined ? { updatedInput: req.updatedInput } : {}),
|
|
2120
2203
|
};
|
|
2121
|
-
const out = await resumeCheckpoint(cp.sessionId, req.decision, req.note, "human", req.httpReq, undefined, binding, undefined, true);
|
|
2204
|
+
const out = await resumeCheckpoint(cp.sessionId, req.decision, req.note, "human", req.httpReq, undefined, binding, undefined, true, { principal: req.principal, explicitOperator: false });
|
|
2122
2205
|
return { status: out.status, body: out.body };
|
|
2123
2206
|
}
|
|
2124
2207
|
const isRunLiveOnThisReplica = (taskId) => inflightRuns.has(taskId) || steerableRuns.has(taskId);
|
|
@@ -2162,22 +2245,28 @@ export function isCredentialGatedRewrite(method, url) {
|
|
|
2162
2245
|
if (m === "POST") {
|
|
2163
2246
|
return (url === "/v1/adoption" ||
|
|
2164
2247
|
url.startsWith("/v1/rules/cc-import/") ||
|
|
2248
|
+
url.startsWith("/v1/rules/local-import/") ||
|
|
2165
2249
|
url === "/v1/memory/import" ||
|
|
2166
2250
|
url === "/v1/memory/export" ||
|
|
2167
2251
|
url === "/v1/memory/erase" ||
|
|
2168
2252
|
url.startsWith("/v1/memory/origin/entries/"));
|
|
2169
2253
|
}
|
|
2254
|
+
if (m === "PUT")
|
|
2255
|
+
return url === "/v1/admin/memory-optout" || url.startsWith("/v1/admin/memory-optout/");
|
|
2170
2256
|
if (m === "DELETE")
|
|
2171
|
-
return url === "/v1/rules";
|
|
2257
|
+
return url === "/v1/rules" || url.startsWith("/v1/admin/memory-optout/");
|
|
2172
2258
|
if (m === "GET") {
|
|
2173
2259
|
return (/^\/v1\/memory\/entries\/[^/]+\/provenance$/.test(url) ||
|
|
2174
2260
|
url === "/v1/memory/origin/external" ||
|
|
2175
|
-
url === "/v1/memory/origin/clearances"
|
|
2261
|
+
url === "/v1/memory/origin/clearances" ||
|
|
2262
|
+
url === "/v1/admin/memory-optout");
|
|
2176
2263
|
}
|
|
2177
2264
|
return false;
|
|
2178
2265
|
}
|
|
2179
2266
|
const ROUTE_LABEL_PATTERNS = [
|
|
2180
2267
|
[/^\/v1\/runs\/[^/]+\/steer$/, "/v1/runs/:id/steer"],
|
|
2268
|
+
[/^\/v1\/runs\/[^/]+\/memory\/capture-optout$/, "/v1/runs/:id/memory/capture-optout"],
|
|
2269
|
+
[/^\/v1\/runs\/[^/]+\/interrupt$/, "/v1/runs/:id/interrupt"],
|
|
2181
2270
|
[/^\/v1\/runs\/[^/]+\/detach$/, "/v1/runs/:id/detach"],
|
|
2182
2271
|
[/^\/v1\/runs\/[^/]+\/cancel$/, "/v1/runs/:id/cancel"],
|
|
2183
2272
|
[/^\/v1\/runs\/[^/]+\/compact$/, "/v1/runs/:id/compact"],
|
|
@@ -2195,10 +2284,12 @@ const ROUTE_LABEL_PATTERNS = [
|
|
|
2195
2284
|
[/^\/v1\/approvals\/[^/]+\/decide$/, "/v1/approvals/:id/decide"],
|
|
2196
2285
|
[/^\/v1\/approvals\/[^/]+\/exemptions(\/[^/]+)?$/, "/v1/approvals/:id/exemptions"],
|
|
2197
2286
|
[/^\/v1\/sessions\/[^/]+\/(wake|fork|init|notify|events|head|mcp|a2a|policy|settings)$/, "/v1/sessions/:id/$verb"],
|
|
2287
|
+
[/^\/v1\/admin\/memory-optout\/[^/]+$/, "/v1/admin/memory-optout/:principal"],
|
|
2288
|
+
[/^\/v1\/sessions\/[^/]+\/memory\/erase$/, "/v1/sessions/:id/memory/erase"],
|
|
2198
2289
|
[/^\/v1\/sessions\/[^/]+\/sync\/(manifest|entries|plan)$/, "/v1/sessions/:id/sync/$verb"],
|
|
2199
2290
|
[/^\/v1\/sessions\/[^/]+\/sync\/import(\/[^/]+\/entries)?$/, "/v1/sessions/:id/sync/import"],
|
|
2200
2291
|
[/^\/v1\/sessions\/[^/]+\/sync\/blobs(\/[^/]+)?$/, "/v1/sessions/:id/sync/blobs"],
|
|
2201
|
-
[/^\/v1\/sessions\/[^/]+\/sync\/
|
|
2292
|
+
[/^\/v1\/sessions\/[^/]+\/sync\/history\/blobs\/[^/]+$/, "/v1/sessions/:id/sync/history/blobs/:hash"],
|
|
2202
2293
|
[/^\/v1\/sessions\/[^/]+\/workspace(\/[^/]+(\/(tree|file|archive))?)?$/, "/v1/sessions/:id/workspace"],
|
|
2203
2294
|
[/^\/v1\/sessions\/[^/]+$/, "/v1/sessions/:id"],
|
|
2204
2295
|
[/^\/v1\/assistant\/tasks\/[^/]+\/preempt$/, "/v1/assistant/tasks/:id/preempt"],
|
|
@@ -2240,8 +2331,10 @@ const ROUTE_LABEL_LITERALS = new Set([
|
|
|
2240
2331
|
"/v1/adoption",
|
|
2241
2332
|
"/v1/admin/drain",
|
|
2242
2333
|
"/v1/admin/config/refresh",
|
|
2334
|
+
"/v1/admin/memory-optout",
|
|
2243
2335
|
"/v1/admin/memory/consolidation/run", "/v1/admin/memory/consolidation",
|
|
2244
2336
|
"/v1/rules/cc-import/prepare", "/v1/rules/cc-import/redeem",
|
|
2337
|
+
"/v1/rules/local-import/prepare", "/v1/rules/local-import/redeem",
|
|
2245
2338
|
"/v1/rules",
|
|
2246
2339
|
"/.well-known/agent-card.json", "/v1/a2a",
|
|
2247
2340
|
"/v1/agents/roster",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* design/97 R9 — the verify-rounds shape (used by the developer-mode
|
|
2
|
+
* design/97 R9 — the verify-rounds shape (used by the developer-mode independent-verification gate, 1.44) pulled
|
|
3
3
|
* out to a NEUTRAL LEAF: it was three copies of the same anonymous `{ maxRounds: number; costCeilingMicroUsd?:
|
|
4
4
|
* number }` object type (route-ctx.ts ×2, runs.ts `runInBackground`'s public signature) plus four call sites in
|
|
5
5
|
* http/server.ts that each re-derived the same "verify:true → clamp rounds + fold cost ceiling" expression from a
|
|
@@ -75,7 +75,7 @@ export interface TaskRequestBody {
|
|
|
75
75
|
* (MAX_TASK_COST_USD / MAX_TASK_TOKENS) — a caller may ask for less, never more. */
|
|
76
76
|
maxCostUsd?: number;
|
|
77
77
|
maxTokens?: number;
|
|
78
|
-
/** Developer mode (1.44): run the task behind the
|
|
78
|
+
/** Developer mode (1.44): run the task behind the independent verification gate (impl → independent
|
|
79
79
|
* read-only verify → fix loop). Default off. `verifyRounds` is clamped to [1,5] (default 2). Not
|
|
80
80
|
* supported on /v1/tasks/stream (the gate is multi-round, not a single stream). */
|
|
81
81
|
verify?: boolean;
|
|
@@ -100,7 +100,7 @@ export interface TaskRequestBody {
|
|
|
100
100
|
* `TaskSpec.skills`. Merged AFTER the scenario's skills with SCENARIO-WINS on a name clash (the security
|
|
101
101
|
* baseline can never be shadowed by user content — see mergeUserSkills). Caps: ≤10 skills, content ≤32KB
|
|
102
102
|
* each. User skills are user-authored content in the user's OWN principal-isolated task (self-harm
|
|
103
|
-
* surface, not privilege
|
|
103
|
+
* surface, not privilege widening); scenario/center skills remain the only trusted layer. */
|
|
104
104
|
skills?: Array<{
|
|
105
105
|
name: string;
|
|
106
106
|
description: string;
|
|
@@ -163,14 +163,23 @@ export interface TaskRequestBody {
|
|
|
163
163
|
count?: number;
|
|
164
164
|
role?: string;
|
|
165
165
|
};
|
|
166
|
-
/**
|
|
167
|
-
*
|
|
168
|
-
*
|
|
166
|
+
/** S-15 file restore (design/381): with `resumeAt`, ALSO converge the working tree's **agent-edited files**
|
|
167
|
+
* (the tracked set — nothing else is visible to the history, so a user's parallel work is structurally
|
|
168
|
+
* untouchable) to that entry's history boundary. Capture needs no request anymore: first-touch tracking is
|
|
169
|
+
* always on when the deployment wires a history store. Requires a FileHistoryStore. */
|
|
170
|
+
restoreFiles?: boolean;
|
|
171
|
+
/** DV-15: opt-in tolerance for a PARTIAL file restore (default = loud terminal failure carrying the per-file
|
|
172
|
+
* ledger; `true` = keep going and disclose the same ledger on the result's rewindNotes). */
|
|
173
|
+
acceptPartialRestore?: boolean;
|
|
174
|
+
/** RETIRED spelling (whole-tree epoch). Still accepted on the wire: its capture sense (true, no resumeAt) is
|
|
175
|
+
* a tolerated no-op with a deprecation disclosure; its restore sense (true + resumeAt) is a typed rejection
|
|
176
|
+
* naming `restoreFiles` — the restore semantics genuinely changed (whole tree ⇒ tracked set), so that
|
|
177
|
+
* migration is explicit by design (core adjudicates; the server never remaps it silently). */
|
|
169
178
|
rewindFiles?: boolean;
|
|
170
|
-
/** R8 code-only rewind (CC "Restore code" mode
|
|
171
|
-
*
|
|
179
|
+
/** R8 code-only rewind (CC "Restore code" mode): converge the TRACKED set to the history boundary at a prior
|
|
180
|
+
* USER message WITHOUT forking the conversation (the session leaf is untouched — only the files move). The
|
|
172
181
|
* value is the same handle as `resumeAt` (the prompt's taskId); the service resolves it → the entry id. Honored ONLY
|
|
173
|
-
* when `resumeAt` is ABSENT (the two modes are mutually exclusive). Requires the anchor map + a
|
|
182
|
+
* when `resumeAt` is ABSENT (the two modes are mutually exclusive). Requires the anchor map + a FileHistoryStore. */
|
|
174
183
|
rewindFilesTo?: string;
|
|
175
184
|
/** design/131 (core 1.246): per-task resilience INTENT flags. allowDegrade/allowFailover are caller-facing;
|
|
176
185
|
* bypassBreaker is operator-only (resolveSpec drops it for non-operators — a permission downgrade, not a 400). */
|
|
@@ -294,6 +303,17 @@ export interface TaskRequestBody {
|
|
|
294
303
|
* adopt-on-read semantics: a paused run still sees the user's hand-edits and git-pull drops, it just commits
|
|
295
304
|
* nothing. Restriction is the session's DECLARATION, never the plane's structure. */
|
|
296
305
|
memoryWrite?: boolean;
|
|
306
|
+
/** design/383 §2.1(core 7.0.0 片2/3;server S-49):**session 记忆采集 opt-out 声明** —— `"off"` = 「本会话
|
|
307
|
+
* 不进长期记忆」:单成员闭集,**没有** `"on"`(缺席就是照常采集的唯一形)。透传为 `TaskSpec.memory.capture`,
|
|
308
|
+
* 由 core 按部署姿态(`MEMORY_CAPTURE_POLICY`)+ 该 principal 的 `allowMemoryOptOut` verdict 裁:拒 = 403
|
|
309
|
+
* `memory.capture_optout_denied`。**一次性**:声明落一条单向控制面记录,后续 resume 恒不采集(record wins),
|
|
310
|
+
* 同会话重复声明幂等;要回到采集只能开新会话。与 `memoryWrite:false`(本 run 只读平面,可逐 run 切换)
|
|
311
|
+
* **不是一个轴**:那是「这次别写」,这是「这个会话永远别记」。
|
|
312
|
+
* ⚠️ 拼写门**两腿同判、响亮拒**:fresh 400 `request.field_invalid`;resume 重放同判(不做 resume 降级 ——
|
|
313
|
+
* 把一条隐私请求按打字错误静默丢掉恰是 core 禁的方向;core 的 `config.memory_capture_spelling` 是第二道墙)。
|
|
314
|
+
* 记忆面暗的部署(引擎未接线 / 多租户)上本键随 `memory` 整体缺席而无处落 —— 那里本就零采集。
|
|
315
|
+
* Rides the persisted body onto resume legs(与 memoryWrite 同姿势)。 */
|
|
316
|
+
memoryCapture?: "off";
|
|
297
317
|
/** 142-S4 projectId 线程化(design/142 §2):这个 run 归属的项目(center 登记簿键,generic lowercase
|
|
298
318
|
* UUID — core S1 `resolveProjectId` marker 或 S3 无仓 mint 的产物;客户端只透传,零铸造权威)。是「哪个
|
|
299
319
|
* 项目」的选择器,不是身份/capability — scope 的 tenant 段永远来自 verified principal。SHAPE 门在
|
|
@@ -387,4 +407,17 @@ export type DecideBinding = {
|
|
|
387
407
|
/** design/37 edit: operator-corrected tool args, applied by core AFTER the binding check, on approve only. */
|
|
388
408
|
updatedInput?: unknown;
|
|
389
409
|
};
|
|
410
|
+
/** S-02([5522]④→[5525] 坐标轮换判定):409 `approval_stale` 拒体上的 additive 机读指路 ——
|
|
411
|
+
* **本会话当前 pending** 的 D-1 回显坐标,让持旧坐标的壳一跳重定位(免重拉列表)。
|
|
412
|
+
* 键名/键形与 GET /v1/approvals 的 pending 行逐字同名(壳复用同一解析)。
|
|
413
|
+
* 🔴 恒**不含** checkpointToken(runs.ts §12-C:resume 凭证从不外发);只在当前 pending **在场**、
|
|
414
|
+
* 属 tool_approval、且已过路由级 owner 门的域内铸 —— 无 pending / 非工具门 / 读失败 ⇒ 键缺席(不造键)。 */
|
|
415
|
+
export type ApprovalStaleCurrentPending = {
|
|
416
|
+
/** 当前 pending 被门住的工具名(与 pending 行的 `toolName` 同源同值)。 */
|
|
417
|
+
toolName: string;
|
|
418
|
+
/** 当前 pending 的 `pendingAction.toolCallId` —— 壳重定位后 decide 时回显的 D-1 锚。 */
|
|
419
|
+
boundCallId: string;
|
|
420
|
+
/** 当前 pending 的 server 铸 `boundInputHash`(行上有才带;逐字回显,壳不重算)。 */
|
|
421
|
+
boundInputHash?: string;
|
|
422
|
+
};
|
|
390
423
|
//# sourceMappingURL=wire-types.d.ts.map
|
|
@@ -44,7 +44,7 @@ export interface LeaderEndpoint {
|
|
|
44
44
|
status: number;
|
|
45
45
|
body: object;
|
|
46
46
|
} | null>;
|
|
47
|
-
/**
|
|
47
|
+
/** 交叉复查 B-1(CRITICAL):the number of leader runs still RUNNING in the background — the drain gate
|
|
48
48
|
* counts them (a SIGTERM used to see 0 and hard-shut mid-leader-run).
|
|
49
49
|
*
|
|
50
50
|
* 🔴 刻意**只数本副本**(即使 store 在场):drain 门问的是「这个进程还在驱动几条 run」,不是「全集群
|
package/dist/leader/leader.d.ts
CHANGED
|
@@ -94,7 +94,7 @@ export interface LeaderDeps {
|
|
|
94
94
|
maxRepairs?: number;
|
|
95
95
|
};
|
|
96
96
|
/** core 1.72 native L3a (design/54 §4): when set, each worker runs via `runWithVerification` (run the module +
|
|
97
|
-
* an
|
|
97
|
+
* an INDEPENDENT DECORRELATED verifier tries to break it reading the diff/workspace + a bounded fix-loop)
|
|
98
98
|
* instead of plain fan-out. The worker runner's `models` catalog MUST carry the heterogeneous `verifierModel`
|
|
99
99
|
* (decorrelation = deployment contract). Mutually exclusive with `moduleGate` (this IS the native version). */
|
|
100
100
|
verifyWorker?: VerifyConfig;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* fixes the `OracleResult` shape + the read-only/identity contract; the composition lives HERE so the core type
|
|
7
7
|
* never grows a discriminated union.
|
|
8
8
|
*
|
|
9
|
-
* Hardened by the
|
|
9
|
+
* Hardened by the cross-review round (§10):
|
|
10
10
|
* - §10.1 HERMETIC grade: the grader tree is reset to a clean base (`git reset --hard <integBase> && git clean
|
|
11
11
|
* -fdx`) BEFORE applying the worker's LATEST full `base..HEAD` diff each call — so a 2nd/3rd attempt never
|
|
12
12
|
* applies cumulatively onto an already-applied tree (the BROKEN finding). The diff is recomputed fresh every
|
|
@@ -63,7 +63,7 @@ export interface RepairOracleCfg {
|
|
|
63
63
|
};
|
|
64
64
|
/** fork1.2 — paths the candidate patch must NOT touch (the seeded hidden-oracle / test paths).
|
|
65
65
|
* The §10.2 factory lane OMITs the engine's path-level probe, so a patch that EDITS the grader's oracle could
|
|
66
|
-
*
|
|
66
|
+
* rewrite the grade and get rubber-stamped as `candidate_only`. A patch touching one of these is REFUSED
|
|
67
67
|
* as `needs_human_oracle` (surfaced for a human, never a silent candidate). Matched by exact path or subtree. */
|
|
68
68
|
oraclePaths?: string[];
|
|
69
69
|
/** 🔴 council 2026-06-17 — the seeded hidden-oracle files (path + content). The hermetic `git clean -fdx`
|
|
@@ -36,7 +36,7 @@ export function mkRepairOracle(cfg) {
|
|
|
36
36
|
if (tampered) {
|
|
37
37
|
cfg.log?.("repair_oracle_tampering_guard", { path: tampered });
|
|
38
38
|
cfg.onGraded?.({ diff: diff.patch, hash: diffHash, passed: false });
|
|
39
|
-
return { tier: "none", passed: false, flaky: false, retries: 0, trace: `candidate patch touches oracle/test path '${tampered}' — refusing to grade (fork1.2 test-
|
|
39
|
+
return { tier: "none", passed: false, flaky: false, retries: 0, trace: `candidate patch touches oracle/test path '${tampered}' — refusing to grade (fork1.2 test-alteration guard)` };
|
|
40
40
|
}
|
|
41
41
|
if (lastGradedHash !== undefined && diffHash === lastGradedHash) {
|
|
42
42
|
cfg.log?.("repair_oracle_stale_diff", { hash: diffHash });
|
package/dist/main.js
CHANGED
|
@@ -30,6 +30,7 @@ import { setRedactionObserver, redactSecrets } from "./trace/redact.js";
|
|
|
30
30
|
import { RateLimiter } from "./observability/rate-limit.js";
|
|
31
31
|
import { createHttpServer, explicitOperatorOk, hasServiceAuth } from "./http/server.js";
|
|
32
32
|
import { exportMemoryScope } from "./memory-export.js";
|
|
33
|
+
import { workflowModelAllowlistFor } from "./task-workflow.js";
|
|
33
34
|
import { createMemoryBundleFaces } from "./memory-bundle-engine.js";
|
|
34
35
|
import { backendOwnsControlPlane, createMemoryComplianceFaces, createMemoryOriginFaces } from "./memory-operator-faces.js";
|
|
35
36
|
import { performMemorySync } from "./memory-sync.js";
|
|
@@ -134,7 +135,7 @@ async function main() {
|
|
|
134
135
|
if (adoptionBoot.scanned > 0 || adoptionBoot.error !== undefined) {
|
|
135
136
|
logger.info("adoption_boot_scan", { ...adoptionBoot });
|
|
136
137
|
}
|
|
137
|
-
const { brain, pricing, counterDegradeHook, costQuota, modelUsageTracker, promptManifestTracker, fleetUsage, fleetLease, tracer, sideQueryAccounting, toolResultStore, sessionPolicyStore,
|
|
138
|
+
const { brain, pricing, counterDegradeHook, costQuota, modelUsageTracker, promptManifestTracker, fleetUsage, fleetLease, tracer, sideQueryAccounting, toolResultStore, sessionPolicyStore, fileHistoryStore, } = createBudgetAndTracing({ config, logger, metrics, backend, breakerState });
|
|
138
139
|
const permissionRuleStores = config.permissionRulesEnabled && backend ? backend.permissionRule() : undefined;
|
|
139
140
|
const ruleConsent = permissionRuleStores ? createRuleConsentLane(permissionRuleStores) : undefined;
|
|
140
141
|
if (config.permissionRulesEnabled && permissionRuleStores === undefined) {
|
|
@@ -163,7 +164,8 @@ async function main() {
|
|
|
163
164
|
getParkedRedeem: () => parkedAskRedeem,
|
|
164
165
|
ruleScopeRootFor: (sessionId) => cardRuleScopeRoot(sessionId !== undefined ? perSessionCwd.get(sessionId) : undefined, config),
|
|
165
166
|
});
|
|
166
|
-
const
|
|
167
|
+
const memoryOptOutGrantStore = backend?.memoryOptOutGrant();
|
|
168
|
+
const { principalCaps, centerRuntimeCapsResolver, runtimeCapsResolver } = createRuntimeCaps({ config, logger, memoryOptOutGrant: memoryOptOutGrantStore });
|
|
167
169
|
const orgMemoryAdmission = createOrgMemoryAdmissionWiring({ config, logger, metrics });
|
|
168
170
|
const sharedMemoryStore = orgMemoryAdmission.directory !== undefined
|
|
169
171
|
? backend?.sharedMemoryStore?.(createSharedMemoryScopeAuthorizer({
|
|
@@ -238,12 +240,14 @@ async function main() {
|
|
|
238
240
|
retentionExecutorWired: config.retentionSweep.intervalSec > 0 && retentionExecutor !== undefined && retentionLaneStore !== undefined,
|
|
239
241
|
});
|
|
240
242
|
const mcpRevocations = configCenter.takeMcpRevocations();
|
|
243
|
+
const workflowModelAllowlistSnapshot = workflowModelAllowlistFor(config) ?? [];
|
|
241
244
|
const runnerDeps = createRunnerDeps({
|
|
242
245
|
hands: commitHands,
|
|
243
246
|
mcpRevocations,
|
|
244
247
|
config, logger, metrics, localRoot, promptSource: configCenter.promptSource, rosterStore, backgroundAgentStore, mailboxStore, usageWindowStore, brain,
|
|
245
248
|
pricing, tracer, outcomeSink, elicitation, question, toolApproval, sessionStore, memoryEngine,
|
|
246
|
-
memorySyncRunner, toolResultStore: runnerOffloadStore, sessionPolicyStore, runtimeCapsResolver,
|
|
249
|
+
memorySyncRunner, toolResultStore: runnerOffloadStore, sessionPolicyStore, runtimeCapsResolver, fileHistoryStore,
|
|
250
|
+
legacyRewindBoundaryProbe: backend?.legacyRewindBoundaryProbe ? backend.legacyRewindBoundaryProbe.bind(backend) : undefined,
|
|
247
251
|
permissionRuleStore: permissionRuleStores?.provider,
|
|
248
252
|
executionEnvFactory, lspManager, fleetBus, deploymentHooks, workflowRunStore, workflowJournalStore,
|
|
249
253
|
workflowAgentRegistry, workflowNotifyGate, workflowCompletionInbox, deliverWorkflowCompletion, orgMemoryAdmission,
|
|
@@ -452,7 +456,7 @@ async function main() {
|
|
|
452
456
|
let runDenySweep;
|
|
453
457
|
const reaper = startReapers({
|
|
454
458
|
config, logger, metrics, localRoot, backend, subRunner, runStore, checkpointStore,
|
|
455
|
-
rateLimiter, costQuota, toolResultStore,
|
|
459
|
+
rateLimiter, costQuota, toolResultStore, fileHistoryStore, taskAttachmentStore, imageBakes, worktreeReap,
|
|
456
460
|
workflowNotifyGate, workflowRecoverOpts, workflowJournalStore, sqlWorkflowRunStore, workflowNotifyJournal, rosterStore,
|
|
457
461
|
backgroundAgentStore, mailboxStore, toolApproval, permissionRuleStores,
|
|
458
462
|
getRunDenySweep: () => runDenySweep,
|
|
@@ -521,7 +525,7 @@ async function main() {
|
|
|
521
525
|
deviceStore: deviceLane?.store,
|
|
522
526
|
dropSessionScoped,
|
|
523
527
|
config, logger, metrics, localRoot, backend, sessionStore, runStore, checkpointStore, toolResultStore,
|
|
524
|
-
resumeAnchorStore, approvalExemptionStore, sessionPolicyStore, taskAttachmentStore,
|
|
528
|
+
resumeAnchorStore, approvalExemptionStore, sessionPolicyStore, taskAttachmentStore, fileHistoryStore,
|
|
525
529
|
workflowCompletionInbox, taskListLane,
|
|
526
530
|
});
|
|
527
531
|
const leaderEndpoint = createLeaderFace({ config, logger, brain, pricing, executionEnvFactory, toolResultStore, sessionStore, checkpointStore, governanceSeams, backend });
|
|
@@ -559,7 +563,7 @@ async function main() {
|
|
|
559
563
|
checkpointStore,
|
|
560
564
|
sessionPolicyStore: sessionPolicyStore ? sessionPolicyStore : undefined,
|
|
561
565
|
ruleConsent,
|
|
562
|
-
|
|
566
|
+
fileHistoryStore: fileHistoryStore ? fileHistoryStore : undefined,
|
|
563
567
|
toolResultStore,
|
|
564
568
|
taskAttachmentStore: taskAttachmentStore ? taskAttachmentStore : undefined,
|
|
565
569
|
backgroundAgentStore: backgroundAgentStore ? backgroundAgentStore : undefined,
|
|
@@ -606,6 +610,7 @@ async function main() {
|
|
|
606
610
|
memoryCompliance: memoryComplianceFaces,
|
|
607
611
|
memoryOriginFace: memoryOriginFaces,
|
|
608
612
|
memoryConsolidation: memoryConsolidationFaces,
|
|
613
|
+
memoryOptOutGrant: memoryOptOutGrantStore,
|
|
609
614
|
orgMemoryDirectory: orgMemoryAdmission.directory,
|
|
610
615
|
sharedMemoryStore: sharedMemoryStore ? sharedMemoryStore : undefined,
|
|
611
616
|
sessionMirrorRuling: principalCaps
|
|
@@ -639,6 +644,7 @@ async function main() {
|
|
|
639
644
|
modelReady: () => configCenter.modelReady(),
|
|
640
645
|
scenarioDetails,
|
|
641
646
|
workflowsCapable,
|
|
647
|
+
workflowModelAllowlist: workflowModelAllowlistSnapshot,
|
|
642
648
|
staticWiring,
|
|
643
649
|
memoryPosture,
|
|
644
650
|
instanceId,
|
|
@@ -678,6 +684,7 @@ async function main() {
|
|
|
678
684
|
sessionEnvSelection,
|
|
679
685
|
lockedKeys: governanceSeams.lockedKeys,
|
|
680
686
|
liveQuestionFace: question,
|
|
687
|
+
approverSeat: createRunnerDepsOnAsk(toolApproval),
|
|
681
688
|
});
|
|
682
689
|
const runnerFor = (spec) => pickHandsRunner(handsLanes.laneOf(spec), { full: runner, handsless: handslessRunner });
|
|
683
690
|
const sideQuery = createSideQueryLane({ brain, config, getKeyResolver: () => configCenter.getKeyResolver() });
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* HTTP 面诚实 501。
|
|
30
30
|
*
|
|
31
31
|
* 🔴 首版把这件事当成**运行期**事实(照常挂载,让 core 每次抛 `memory.export_incomplete` / 422),
|
|
32
|
-
* 被 codex
|
|
32
|
+
* 被 codex 交叉复审驳倒(#277 提货批 [medium],验真后修):`typeof backend.exportSnapshotOf === "function"`
|
|
33
33
|
* 是一次**属性检查**,boot 期就判得出;而且它是**永久**缺席(换后端才会变),不是瞬时状态。照旧挂着
|
|
34
34
|
* 就成了「能力位说 yes、每一次调用都确定性失败」——本仓「says yes ⟺ route works」是结构性承诺,
|
|
35
35
|
* 一个恒假的 yes 会让壳给用户开出一条走不通的迁移流程。
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* Runner 每任务现构的引擎会看到**两个不同的控制面**。
|
|
24
24
|
*
|
|
25
25
|
* ⇒ 裁:`controlPlaneRoot` 缺席 ⇒ 本工厂返回 **undefined**,两口整个不挂载,HTTP 面诚实 501。今天满足这一
|
|
26
|
-
* 条的只有 core 自带的 `FileMemoryEngineBackend`(
|
|
26
|
+
* 条的只有 core 自带的 `FileMemoryEngineBackend`(它把控制面写死在 config-root 一侧);本仓两只 SQL 记忆
|
|
27
27
|
* 孪生(`plugins/memory-engine-{pg,tidb}.ts`)没有这个面 ⇒ 在那些部署上两口不挂。SQL 控制面是 core 的候升件
|
|
28
28
|
* (design/316 §0b-4 咨询单),**绝不**在本层为它们现造一个「够用的」控制面 —— 那是把一个 core 拒绝生产的
|
|
29
29
|
* 半吊子治理面自己造出来,与 bundle 那条「a governance-less export is the laundering shape」同族。
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
*
|
|
37
37
|
* 判据是一次**属性检查**、boot 期就判得出、而且是**永久**缺席(换后端才会变)——不是瞬时状态。照旧挂着
|
|
38
38
|
* 就成了「能力位说 yes、每一次调用都确定性失败」,而本仓「says yes ⟺ route works」是结构性承诺。
|
|
39
|
-
* (这条纪律是 #264 提货批被 codex
|
|
39
|
+
* (这条纪律是 #264 提货批被 codex 交叉复审驳倒后立的,见 memory-bundle-engine.ts 头注。)
|
|
40
40
|
*
|
|
41
41
|
* ⚠️ **刻意不把审计/托管/证据三个可选面编进构造判定**:`committedSnapshotOf` / `custodyOf` 缺席时 core
|
|
42
42
|
* 明写要诚实答 `binding:"unknown"` / `contentState:"capability-absent"` / `custody:"capability-absent"`
|
|
@@ -70,7 +70,7 @@ export interface MemoryComplianceFaces {
|
|
|
70
70
|
}) => Promise<MemoryErasureAttestation>;
|
|
71
71
|
}
|
|
72
72
|
/**
|
|
73
|
-
* **选择子替身**的拦截谓词(codex
|
|
73
|
+
* **选择子替身**的拦截谓词(codex 交叉复审 [critical],亲验复现后修 —— 复现器与结论逐条在
|
|
74
74
|
* `test/memory-compliance-http.test.ts` 的同名 describe 与 `test/memory-operator-faces.test.ts` 里)。
|
|
75
75
|
*
|
|
76
76
|
* ## 病(在 core 5.57.0 上实测,不是纸面推演)
|
|
@@ -82,7 +82,7 @@ export interface MemoryComplianceFaces {
|
|
|
82
82
|
* `__proto__` 那一下改的是克隆体的**原型**,于是这个键从 `Object.keys` 里消失;
|
|
83
83
|
* · core 的 `erasureRequestInvalid` 数的是 `Object.keys` ⇒ 只看见一个 `scope` ⇒ **判合法**;
|
|
84
84
|
* · 而两条执行腿的分派都写作 `"ids" in select`(engine.js:477 降级腿、file-backend.js:2614 证据腿),
|
|
85
|
-
* `in` **查原型链** ⇒ 继承来的 `ids`
|
|
85
|
+
* `in` **查原型链** ⇒ 继承来的 `ids` 赢,删的是不当调用方点名的那批 id;
|
|
86
86
|
* · 收执里的 `select` / `selectHash` 记的却是那个自有的 `scope`。
|
|
87
87
|
* ⇒ **删掉的东西与凭据上写的不是同一批**,而这一口的全部意义就是那份可归档的凭据;删除不可回滚。
|
|
88
88
|
*
|
|
@@ -94,7 +94,7 @@ export interface MemoryComplianceFaces {
|
|
|
94
94
|
* 本仓禁止的形,而且悄悄改写调用方的请求会让它以为自己删的是别的东西)。
|
|
95
95
|
*
|
|
96
96
|
* 两个执法点共用**这一只**谓词:路由拿它出 400(wire 可见、有钉),seam 拿它 fail-closed 兜底(seam 是
|
|
97
|
-
* 可导出模块,不能靠「今天只有一个调用方」这句话来安全;走到那一臂 =
|
|
97
|
+
* 可导出模块,不能靠「今天只有一个调用方」这句话来安全;走到那一臂 = 路由的门被跳过了 = 装配 bug,
|
|
98
98
|
* 500 fail-loud 是对的)。刻意不做「只在 seam 拦」:那样 wire 上就没有一句能测的诚实拒。
|
|
99
99
|
*
|
|
100
100
|
* 走法是**迭代**而非递归:体的深度只受体积上限约束,一个深嵌套的 JSON 能把递归版打爆栈(把一个
|