@sema-agent/server 7.50.0 → 7.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +83 -20
- package/dist/adoption/plan.d.ts +4 -4
- package/dist/adoption/plan.js +11 -0
- package/dist/approval-card.d.ts +26 -2
- package/dist/approval-card.js +9 -0
- package/dist/approval-hmac.d.ts +1 -1
- package/dist/approval-reconciler.d.ts +2 -2
- package/dist/approval-reconciler.js +1 -1
- package/dist/bench/l8/artifact.d.ts +1 -1
- package/dist/bench/s1/arms.d.ts +1 -1
- package/dist/bench/s1/live-deps.d.ts +1 -1
- package/dist/bench/s1/oracle.d.ts +1 -1
- package/dist/bench/s1/row.d.ts +1 -1
- package/dist/boot/budget-tracing.d.ts +1 -1
- package/dist/boot/budget-tracing.js +2 -5
- package/dist/boot/coordinators.js +3 -1
- package/dist/boot/deferred-sandbox-path-env.d.ts +1 -1
- package/dist/boot/device-lane.d.ts +79 -0
- package/dist/boot/device-lane.js +63 -0
- package/dist/boot/engine-lease.d.ts +1 -1
- package/dist/boot/execution-env.d.ts +48 -2
- package/dist/boot/execution-env.js +57 -5
- package/dist/boot/governance-seams.d.ts +2 -2
- package/dist/boot/leader.d.ts +1 -1
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-consolidation.d.ts +6 -6
- package/dist/boot/org-memory.d.ts +1 -1
- package/dist/boot/parked-revive-gate.d.ts +3 -3
- package/dist/boot/reapers.d.ts +2 -2
- package/dist/boot/reapers.js +17 -4
- package/dist/boot/resolve-spec.d.ts +15 -0
- package/dist/boot/resolve-spec.js +40 -15
- package/dist/boot/retention-lane.d.ts +2 -2
- package/dist/boot/runner-deps.d.ts +17 -7
- package/dist/boot/runner-deps.js +4 -2
- package/dist/boot/runtime-caps.d.ts +23 -0
- package/dist/boot/runtime-caps.js +24 -2
- package/dist/boot/session-faces.d.ts +6 -1
- package/dist/boot/session-faces.js +17 -3
- package/dist/boot/shutdown.d.ts +8 -0
- package/dist/boot/shutdown.js +3 -1
- package/dist/boot/stores.js +40 -1
- package/dist/boot/task-list-lane.d.ts +2 -2
- package/dist/brain.js +51 -31
- package/dist/budget.d.ts +2 -2
- package/dist/capabilities/center-plugins.d.ts +1 -1
- package/dist/capabilities/collab-workflows.d.ts +1 -1
- package/dist/capabilities/hands-lane.d.ts +3 -3
- package/dist/capabilities/scenarios.d.ts +3 -3
- package/dist/capabilities/skills.d.ts +1 -1
- package/dist/config-center/hot-keys-registry.js +5 -0
- package/dist/config-center/http-client.d.ts +2 -2
- package/dist/config-center/read-face.d.ts +1 -1
- package/dist/config-center/restart-signal.d.ts +1 -1
- package/dist/config-center/types.d.ts +10 -3
- package/dist/config-invariants.d.ts +2 -2
- package/dist/config-invariants.js +18 -0
- package/dist/config-types.d.ts +90 -18
- package/dist/config.js +91 -19
- package/dist/deployment-governance.d.ts +1 -1
- package/dist/device-enrollment.d.ts +125 -0
- package/dist/device-enrollment.js +156 -0
- package/dist/device-store.d.ts +385 -0
- package/dist/device-store.js +407 -0
- package/dist/device-ws-hub.d.ts +182 -0
- package/dist/device-ws-hub.js +1012 -0
- package/dist/device-ws-protocol.d.ts +429 -0
- package/dist/device-ws-protocol.js +464 -0
- package/dist/env-facts.d.ts +5 -2
- package/dist/env-facts.js +1 -0
- package/dist/execution-lane-caps.d.ts +152 -0
- package/dist/execution-lane-caps.js +166 -0
- package/dist/fleet/fleet-bus.d.ts +1 -1
- package/dist/fleet/fleet-reconciler.d.ts +1 -1
- package/dist/fleet/fleet-terminal-window.d.ts +1 -1
- package/dist/http/active-run-conflict.d.ts +2 -2
- package/dist/http/principal-gate.d.ts +1 -1
- package/dist/http/route-ctx.d.ts +24 -4
- package/dist/http/routes/admin-memory-optout.d.ts +48 -0
- package/dist/http/routes/admin-memory-optout.js +75 -0
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/approvals-assistant.js +21 -21
- package/dist/http/routes/capabilities.js +27 -11
- package/dist/http/routes/diagnostics.d.ts +1 -1
- package/dist/http/routes/leader.d.ts +1 -1
- package/dist/http/routes/memory-bundle.d.ts +1 -1
- package/dist/http/routes/memory-bundle.js +3 -1
- package/dist/http/routes/memory-compliance.d.ts +4 -4
- package/dist/http/routes/memory-origin.d.ts +4 -4
- package/dist/http/routes/memory-origin.js +3 -1
- package/dist/http/routes/memory-policy.js +6 -2
- package/dist/http/routes/retention-ops.d.ts +1 -1
- package/dist/http/routes/rules.d.ts +5 -2
- package/dist/http/routes/rules.js +84 -5
- package/dist/http/routes/run-memory-capture.d.ts +34 -0
- package/dist/http/routes/run-memory-capture.js +97 -0
- package/dist/http/routes/runs.d.ts +1 -0
- package/dist/http/routes/runs.js +212 -6
- package/dist/http/routes/session-sync.d.ts +4 -6
- package/dist/http/routes/session-sync.js +60 -47
- package/dist/http/routes/sessions.js +61 -188
- package/dist/http/routes/shared-memory.d.ts +1 -1
- package/dist/http/routes/tasks.js +1 -1
- package/dist/http/routes/workflows.js +19 -0
- package/dist/http/server.d.ts +49 -13
- package/dist/http/server.js +109 -13
- package/dist/http/verify-rounds.d.ts +1 -1
- package/dist/http/wire-types.d.ts +41 -8
- package/dist/leader/endpoint.d.ts +1 -1
- package/dist/leader/leader.d.ts +1 -1
- package/dist/leader/repair-oracle.d.ts +2 -2
- package/dist/leader/repair-oracle.js +1 -1
- package/dist/leader/wire.js +4 -2
- package/dist/main.js +23 -9
- package/dist/memory-bundle-engine.d.ts +1 -1
- package/dist/memory-operator-faces.d.ts +5 -5
- package/dist/memory-origin-fence.d.ts +50 -0
- package/dist/memory-origin-fence.js +15 -0
- package/dist/memory-posture.d.ts +13 -1
- package/dist/memory-posture.js +1 -0
- package/dist/memory-scope.d.ts +6 -1
- package/dist/memory-scope.js +3 -2
- package/dist/model-select.d.ts +2 -2
- package/dist/observability/fail-open.d.ts +17 -5
- package/dist/observability/fail-open.js +17 -5
- package/dist/orchestration/hardened-vm-runner.d.ts +9 -2
- package/dist/orchestration/hardened-vm-runner.js +11 -1
- package/dist/orchestration/hardened-vm-worker-runner.js +2 -2
- package/dist/orchestration/workflow-completion-inbox.d.ts +2 -2
- package/dist/plugins/background-shell-support.d.ts +2 -2
- package/dist/plugins/blob-backend.d.ts +7 -2
- package/dist/plugins/blob-backend.js +22 -18
- package/dist/plugins/caching-session-store.d.ts +7 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +2 -2
- package/dist/plugins/device-store-sql.d.ts +130 -0
- package/dist/plugins/device-store-sql.js +574 -0
- package/dist/plugins/file-history-store-sql.d.ts +170 -0
- package/dist/plugins/file-history-store-sql.js +827 -0
- package/dist/plugins/file-run-store.d.ts +44 -5
- package/dist/plugins/file-run-store.js +85 -13
- package/dist/plugins/fork-routing-session-store.d.ts +1 -1
- package/dist/plugins/fork-routing-session-store.js +2 -2
- package/dist/plugins/leader-run-store-sql.d.ts +1 -1
- package/dist/plugins/local-session-store.d.ts +9 -1
- package/dist/plugins/memory-embedder-fingerprint.d.ts +1 -1
- package/dist/plugins/memory-optout-grant-store-sql.d.ts +139 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +157 -0
- package/dist/plugins/memory-origin-law.d.ts +2 -2
- package/dist/plugins/memory-run-store.d.ts +4 -3
- package/dist/plugins/memory-run-store.js +2 -1
- package/dist/plugins/permission-rule-store-file.d.ts +16 -6
- package/dist/plugins/permission-rule-store-file.js +77 -13
- package/dist/plugins/permission-rule-store-sql.d.ts +156 -8
- package/dist/plugins/permission-rule-store-sql.js +123 -21
- package/dist/plugins/pg-pool.js +59 -0
- package/dist/plugins/pg-safe-json.d.ts +1 -1
- package/dist/plugins/remote-env-device.d.ts +271 -0
- package/dist/plugins/remote-env-device.js +727 -0
- package/dist/plugins/remote-env-k8s.d.ts +1 -1
- package/dist/plugins/remote-scratchpad.js +1 -1
- package/dist/plugins/retention-lane-store-sql.d.ts +3 -3
- package/dist/plugins/retention-store-sql.d.ts +7 -7
- package/dist/plugins/retention-store-sql.js +6 -0
- package/dist/plugins/run-store-sql.d.ts +9 -3
- package/dist/plugins/run-store-sql.js +2 -2
- package/dist/plugins/send-user-file.d.ts +1 -1
- package/dist/plugins/session-placement.d.ts +1 -1
- package/dist/plugins/sql-errors.d.ts +1 -1
- package/dist/plugins/store-backend.d.ts +68 -29
- package/dist/plugins/store-backend.js +78 -15
- package/dist/plugins/store-contracts.d.ts +5 -3
- package/dist/plugins/task-list-store-sql.d.ts +1 -1
- package/dist/plugins/tidb-pool.js +59 -0
- package/dist/plugins/web-search.d.ts +1 -1
- package/dist/prompts-domain-validate.js +1 -1
- package/dist/resource-suspend.d.ts +1 -1
- package/dist/resource-window.d.ts +3 -3
- package/dist/rules-consent.d.ts +231 -9
- package/dist/rules-consent.js +411 -13
- package/dist/run-local.js +1 -0
- package/dist/runs.d.ts +15 -1
- package/dist/runs.js +19 -0
- package/dist/runtime-caps-resolver.d.ts +36 -1
- package/dist/runtime-caps-resolver.js +25 -0
- package/dist/runtime-governance.d.ts +1 -1
- package/dist/security.d.ts +5 -5
- package/dist/security.js +1 -1
- package/dist/session-sync.d.ts +52 -37
- package/dist/session-sync.js +19 -16
- package/dist/shared-memory-scope-authorizer.d.ts +1 -1
- package/dist/sighup-idle.d.ts +1 -1
- package/dist/spec-fields.d.ts +22 -1
- package/dist/spec-fields.js +11 -0
- package/dist/store-live-probe.d.ts +2 -2
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-cwd.d.ts +25 -0
- package/dist/task-cwd.js +3 -0
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-settings.d.ts +3 -3
- package/dist/task-settings.js +3 -1
- package/dist/task-workflow.d.ts +1 -1
- package/dist/text-bidi.d.ts +2 -2
- package/dist/tool-approval.d.ts +191 -9
- package/dist/tool-approval.js +248 -29
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/engine-notice-wire.d.ts +6 -4
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/ledger-events.d.ts +1 -1
- package/dist/trace/ledger-sink.d.ts +2 -2
- package/dist/trace/project.d.ts +3 -2
- package/dist/trace/project.js +1 -0
- package/dist/turn-activity.d.ts +1 -1
- package/dist/wall-clock-jump-guard.d.ts +3 -3
- package/package.json +2 -2
- package/dist/http/tar.d.ts +0 -17
- package/dist/http/tar.js +0 -53
- package/dist/http/workspace-content.d.ts +0 -11
- package/dist/http/workspace-content.js +0 -20
- package/dist/plugins/file-snapshot-store-sql.d.ts +0 -170
- package/dist/plugins/file-snapshot-store-sql.js +0 -213
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,
|
|
@@ -244,6 +248,7 @@ export function createHttpServer(rawDeps) {
|
|
|
244
248
|
res.end();
|
|
245
249
|
});
|
|
246
250
|
});
|
|
251
|
+
deps.deviceHub?.attach(server);
|
|
247
252
|
const routeCtxBase = {
|
|
248
253
|
deps,
|
|
249
254
|
registry: { idemCache, inflightRuns, preemptableRuns, cancelledViaVerb, steerableRuns, wakeParkMints, counters },
|
|
@@ -440,6 +445,8 @@ export function createHttpServer(rawDeps) {
|
|
|
440
445
|
return;
|
|
441
446
|
if (await handleRunVerbs(req, res, url, ctx))
|
|
442
447
|
return;
|
|
448
|
+
if (await handleRunMemoryCapture(req, res, url, ctx))
|
|
449
|
+
return;
|
|
443
450
|
if (await handleLeader(req, res, url, ctx))
|
|
444
451
|
return;
|
|
445
452
|
if (await handleImages(req, res, url, ctx))
|
|
@@ -458,6 +465,8 @@ export function createHttpServer(rawDeps) {
|
|
|
458
465
|
return;
|
|
459
466
|
if (await handleAdminConfigRefresh(req, res, url, ctx))
|
|
460
467
|
return;
|
|
468
|
+
if (await handleMemoryOptOut(req, res, url, ctx))
|
|
469
|
+
return;
|
|
461
470
|
if (await handleMemoryPolicy(req, res, url, ctx))
|
|
462
471
|
return;
|
|
463
472
|
if (await handleMemoryBundle(req, res, url, ctx))
|
|
@@ -489,7 +498,7 @@ export function createHttpServer(rawDeps) {
|
|
|
489
498
|
function runnerFor(spec) {
|
|
490
499
|
return deps.runnerFor?.(spec) ?? deps.runner;
|
|
491
500
|
}
|
|
492
|
-
async function prepareSpec(req, res, bodyIn, onTypedFailure) {
|
|
501
|
+
async function prepareSpec(req, res, bodyIn, onTypedFailure, legFacts) {
|
|
493
502
|
const body = bodyIn ?? (await readJson(req));
|
|
494
503
|
if (!body || typeof body.objective !== "string") {
|
|
495
504
|
sendError(res, 400, "request.field_invalid", "missing 'objective' string");
|
|
@@ -722,10 +731,22 @@ export function createHttpServer(rawDeps) {
|
|
|
722
731
|
sendError(res, 400, "request.field_invalid", "rewindFiles must be a boolean");
|
|
723
732
|
return null;
|
|
724
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
|
+
}
|
|
725
742
|
if (body.memoryWrite !== undefined && typeof body.memoryWrite !== "boolean") {
|
|
726
743
|
sendError(res, 400, "request.field_invalid", "memoryWrite must be a boolean (false = pause memory writes for this run)");
|
|
727
744
|
return null;
|
|
728
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
|
+
}
|
|
729
750
|
if (body.requireExistingSession !== undefined && typeof body.requireExistingSession !== "boolean") {
|
|
730
751
|
sendError(res, 400, "request.field_invalid", "requireExistingSession must be a boolean");
|
|
731
752
|
return null;
|
|
@@ -807,6 +828,13 @@ export function createHttpServer(rawDeps) {
|
|
|
807
828
|
sendError(res, 400, "request.field_invalid", agentsErr);
|
|
808
829
|
return null;
|
|
809
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
|
+
}
|
|
810
838
|
}
|
|
811
839
|
if (body.interactiveTools !== undefined && typeof body.interactiveTools !== "boolean") {
|
|
812
840
|
sendError(res, 400, "request.field_invalid", "interactiveTools must be a boolean");
|
|
@@ -931,7 +959,7 @@ export function createHttpServer(rawDeps) {
|
|
|
931
959
|
}
|
|
932
960
|
try {
|
|
933
961
|
const auth = deps.authorize ? await deps.authorize({ req, body }) : undefined;
|
|
934
|
-
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 } : {}) });
|
|
935
963
|
return { spec, runner: runnerFor(spec), auth, verify, cascade, jobId: body.jobId, body };
|
|
936
964
|
}
|
|
937
965
|
catch (err) {
|
|
@@ -947,21 +975,52 @@ export function createHttpServer(rawDeps) {
|
|
|
947
975
|
}
|
|
948
976
|
}
|
|
949
977
|
const resumeFleetScope = (req, auth) => req ? (gatedPrincipal(req, deps.config) ?? "default") : (auth.principal ?? "default");
|
|
950
|
-
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) {
|
|
951
979
|
const cs = deps.checkpointStore;
|
|
952
980
|
const token = await cs.findPendingTokenBySession(sessionId);
|
|
953
981
|
if (binding?.checkpointToken && binding.checkpointToken !== token) {
|
|
954
|
-
|
|
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
|
+
});
|
|
955
988
|
const attributable = seen !== null && seen.sessionId === sessionId;
|
|
956
989
|
if (!attributable && seen !== null) {
|
|
957
990
|
deps.logger?.warn?.("approval_stale_token_foreign", { sessionId, tokenSession: seen.sessionId ?? null });
|
|
958
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
|
+
}
|
|
959
1017
|
return {
|
|
960
1018
|
status: 409,
|
|
961
1019
|
body: {
|
|
962
1020
|
error: "the approval you are deciding is no longer current (already resolved or superseded since you viewed it)",
|
|
963
1021
|
errorCode: "approval_stale",
|
|
964
1022
|
...(attributable ? { terminal: "resolved" } : {}),
|
|
1023
|
+
...(currentPending ? { currentPending } : {}),
|
|
965
1024
|
},
|
|
966
1025
|
};
|
|
967
1026
|
}
|
|
@@ -981,6 +1040,13 @@ export function createHttpServer(rawDeps) {
|
|
|
981
1040
|
}
|
|
982
1041
|
if (!cp)
|
|
983
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
|
+
}
|
|
984
1050
|
const decideGateKind = cp.gate?.kind;
|
|
985
1051
|
if (!isApprovalGateKind(decideGateKind)) {
|
|
986
1052
|
const activeForPath = decideGateKind
|
|
@@ -1008,6 +1074,13 @@ export function createHttpServer(rawDeps) {
|
|
|
1008
1074
|
},
|
|
1009
1075
|
};
|
|
1010
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;
|
|
1011
1084
|
if (req !== undefined && deps.backgroundAgentStore !== undefined && deps.parkedReviveTool !== undefined) {
|
|
1012
1085
|
const parked = await decideParkedAgent({
|
|
1013
1086
|
agentStore: deps.backgroundAgentStore,
|
|
@@ -1021,7 +1094,7 @@ export function createHttpServer(rawDeps) {
|
|
|
1021
1094
|
token, scope: cp.scope, sessionId: cp.sessionId, pendingAction: cp.pendingAction,
|
|
1022
1095
|
decision, settledBy, ...(reason !== undefined ? { reason } : {}),
|
|
1023
1096
|
...(binding !== undefined ? { binding: { ...(binding.boundCallId !== undefined ? { boundCallId: binding.boundCallId } : {}), ...(binding.boundInputHash !== undefined ? { boundInputHash: binding.boundInputHash } : {}), ...(binding.updatedInput !== undefined ? { updatedInput: binding.updatedInput } : {}) } } : {}),
|
|
1024
|
-
...(
|
|
1097
|
+
...(boundGrant ? { grantRemember: (rootSessionId) => boundGrant(rootSessionId) } : {}),
|
|
1025
1098
|
...(answer !== undefined ? { answer } : {}),
|
|
1026
1099
|
});
|
|
1027
1100
|
if (parked !== undefined) {
|
|
@@ -1090,7 +1163,7 @@ export function createHttpServer(rawDeps) {
|
|
|
1090
1163
|
settledBy,
|
|
1091
1164
|
};
|
|
1092
1165
|
const verifyRounds = verifyRoundsFromBody(ctx.body);
|
|
1093
|
-
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 } : {}) });
|
|
1094
1167
|
}
|
|
1095
1168
|
async function driveResumeIntoRunLog(args) {
|
|
1096
1169
|
if (args.acceptEarly !== true)
|
|
@@ -1157,6 +1230,17 @@ export function createHttpServer(rawDeps) {
|
|
|
1157
1230
|
? fleetRunPublisher(deps.fleetBus, { runId: taskId, scope: fleetScope, rootTaskId: taskId, ...fleetRunLabels(resumeObjective) })
|
|
1158
1231
|
: undefined;
|
|
1159
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
|
+
}
|
|
1160
1244
|
if (taskId && resumeTaskConfig.resourceSuspend)
|
|
1161
1245
|
recordResumeResourceWindow(taskId, resumeTaskConfig.resourceSuspend);
|
|
1162
1246
|
let fleetSettled = false;
|
|
@@ -1188,7 +1272,7 @@ export function createHttpServer(rawDeps) {
|
|
|
1188
1272
|
const cancelCtrl = new AbortController();
|
|
1189
1273
|
const preemptCtrl = new AbortController();
|
|
1190
1274
|
if (taskId && deps.runStore) {
|
|
1191
|
-
claimedRow = freshRunClaimed ? true : await deps.runStore.markResuming(taskId);
|
|
1275
|
+
claimedRow = freshRunClaimed ? true : await deps.runStore.markResuming(taskId, deps.instanceId ?? "default");
|
|
1192
1276
|
if (!claimedRow)
|
|
1193
1277
|
return { status: 409, body: { error: "run is not in a resumable (suspended) state (already resumed, decided, or expired)", errorCode: "conflict.not_resumable" } };
|
|
1194
1278
|
markChildrenStoppedByUserOnAbort(cancelCtrl.signal, taskId, principal);
|
|
@@ -1604,6 +1688,8 @@ export function createHttpServer(rawDeps) {
|
|
|
1604
1688
|
e.code === "resume.constraint_unprojectable" ||
|
|
1605
1689
|
e.code === "resume.usage_window_exhausted" ||
|
|
1606
1690
|
e.code === "resume.principal_mismatch" ||
|
|
1691
|
+
e.code === "resume.placement_mismatch" ||
|
|
1692
|
+
e.code === "resume.preflight_rejected" ||
|
|
1607
1693
|
e.code.startsWith("wake.") ||
|
|
1608
1694
|
(e.code === "checkpoint.unsupported_version" && checkpointRowRedeemableElsewhere(e.detail?.reason));
|
|
1609
1695
|
if (claimedRow && taskId && deps.runStore) {
|
|
@@ -1633,7 +1719,7 @@ export function createHttpServer(rawDeps) {
|
|
|
1633
1719
|
? (outcome.gate === "policy_ask" ? "approval_binding_mismatch" : "resume_outcome_invalid")
|
|
1634
1720
|
: e.code,
|
|
1635
1721
|
...(e.detail?.field ? { field: e.detail.field } : {}),
|
|
1636
|
-
...(e.code === "resume.usage_window_exhausted" && typeof e.detail?.retryAfterMs === "number" && Number.isFinite(e.detail.retryAfterMs) && e.detail.retryAfterMs > 0
|
|
1722
|
+
...((e.code === "resume.usage_window_exhausted" || e.code === "resume.preflight_rejected") && typeof e.detail?.retryAfterMs === "number" && Number.isFinite(e.detail.retryAfterMs) && e.detail.retryAfterMs > 0
|
|
1637
1723
|
? { retryAfterSec: Math.max(1, Math.ceil(e.detail.retryAfterMs / 1000)) }
|
|
1638
1724
|
: {}),
|
|
1639
1725
|
...(retriable ? { retriable: true } : {}),
|
|
@@ -2115,7 +2201,7 @@ export function createHttpServer(rawDeps) {
|
|
|
2115
2201
|
...(req.gateBoundInputHash !== null ? { boundInputHash: req.gateBoundInputHash } : {}),
|
|
2116
2202
|
...(req.updatedInput !== undefined ? { updatedInput: req.updatedInput } : {}),
|
|
2117
2203
|
};
|
|
2118
|
-
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 });
|
|
2119
2205
|
return { status: out.status, body: out.body };
|
|
2120
2206
|
}
|
|
2121
2207
|
const isRunLiveOnThisReplica = (taskId) => inflightRuns.has(taskId) || steerableRuns.has(taskId);
|
|
@@ -2159,22 +2245,28 @@ export function isCredentialGatedRewrite(method, url) {
|
|
|
2159
2245
|
if (m === "POST") {
|
|
2160
2246
|
return (url === "/v1/adoption" ||
|
|
2161
2247
|
url.startsWith("/v1/rules/cc-import/") ||
|
|
2248
|
+
url.startsWith("/v1/rules/local-import/") ||
|
|
2162
2249
|
url === "/v1/memory/import" ||
|
|
2163
2250
|
url === "/v1/memory/export" ||
|
|
2164
2251
|
url === "/v1/memory/erase" ||
|
|
2165
2252
|
url.startsWith("/v1/memory/origin/entries/"));
|
|
2166
2253
|
}
|
|
2254
|
+
if (m === "PUT")
|
|
2255
|
+
return url === "/v1/admin/memory-optout" || url.startsWith("/v1/admin/memory-optout/");
|
|
2167
2256
|
if (m === "DELETE")
|
|
2168
|
-
return url === "/v1/rules";
|
|
2257
|
+
return url === "/v1/rules" || url.startsWith("/v1/admin/memory-optout/");
|
|
2169
2258
|
if (m === "GET") {
|
|
2170
2259
|
return (/^\/v1\/memory\/entries\/[^/]+\/provenance$/.test(url) ||
|
|
2171
2260
|
url === "/v1/memory/origin/external" ||
|
|
2172
|
-
url === "/v1/memory/origin/clearances"
|
|
2261
|
+
url === "/v1/memory/origin/clearances" ||
|
|
2262
|
+
url === "/v1/admin/memory-optout");
|
|
2173
2263
|
}
|
|
2174
2264
|
return false;
|
|
2175
2265
|
}
|
|
2176
2266
|
const ROUTE_LABEL_PATTERNS = [
|
|
2177
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"],
|
|
2178
2270
|
[/^\/v1\/runs\/[^/]+\/detach$/, "/v1/runs/:id/detach"],
|
|
2179
2271
|
[/^\/v1\/runs\/[^/]+\/cancel$/, "/v1/runs/:id/cancel"],
|
|
2180
2272
|
[/^\/v1\/runs\/[^/]+\/compact$/, "/v1/runs/:id/compact"],
|
|
@@ -2192,10 +2284,12 @@ const ROUTE_LABEL_PATTERNS = [
|
|
|
2192
2284
|
[/^\/v1\/approvals\/[^/]+\/decide$/, "/v1/approvals/:id/decide"],
|
|
2193
2285
|
[/^\/v1\/approvals\/[^/]+\/exemptions(\/[^/]+)?$/, "/v1/approvals/:id/exemptions"],
|
|
2194
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"],
|
|
2195
2289
|
[/^\/v1\/sessions\/[^/]+\/sync\/(manifest|entries|plan)$/, "/v1/sessions/:id/sync/$verb"],
|
|
2196
2290
|
[/^\/v1\/sessions\/[^/]+\/sync\/import(\/[^/]+\/entries)?$/, "/v1/sessions/:id/sync/import"],
|
|
2197
2291
|
[/^\/v1\/sessions\/[^/]+\/sync\/blobs(\/[^/]+)?$/, "/v1/sessions/:id/sync/blobs"],
|
|
2198
|
-
[/^\/v1\/sessions\/[^/]+\/sync\/
|
|
2292
|
+
[/^\/v1\/sessions\/[^/]+\/sync\/history\/blobs\/[^/]+$/, "/v1/sessions/:id/sync/history/blobs/:hash"],
|
|
2199
2293
|
[/^\/v1\/sessions\/[^/]+\/workspace(\/[^/]+(\/(tree|file|archive))?)?$/, "/v1/sessions/:id/workspace"],
|
|
2200
2294
|
[/^\/v1\/sessions\/[^/]+$/, "/v1/sessions/:id"],
|
|
2201
2295
|
[/^\/v1\/assistant\/tasks\/[^/]+\/preempt$/, "/v1/assistant/tasks/:id/preempt"],
|
|
@@ -2237,8 +2331,10 @@ const ROUTE_LABEL_LITERALS = new Set([
|
|
|
2237
2331
|
"/v1/adoption",
|
|
2238
2332
|
"/v1/admin/drain",
|
|
2239
2333
|
"/v1/admin/config/refresh",
|
|
2334
|
+
"/v1/admin/memory-optout",
|
|
2240
2335
|
"/v1/admin/memory/consolidation/run", "/v1/admin/memory/consolidation",
|
|
2241
2336
|
"/v1/rules/cc-import/prepare", "/v1/rules/cc-import/redeem",
|
|
2337
|
+
"/v1/rules/local-import/prepare", "/v1/rules/local-import/redeem",
|
|
2242
2338
|
"/v1/rules",
|
|
2243
2339
|
"/.well-known/agent-card.json", "/v1/a2a",
|
|
2244
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/leader/wire.js
CHANGED
|
@@ -366,7 +366,8 @@ export function createLeaderRunner(cfg) {
|
|
|
366
366
|
};
|
|
367
367
|
const provisionIntegrationSandbox = async () => {
|
|
368
368
|
if (cfg.envFactory) {
|
|
369
|
-
const
|
|
369
|
+
const integSessionId = `leader-integ-${Date.now()}`;
|
|
370
|
+
const env = cfg.envFactory({ sessionId: integSessionId, placementRootSessionId: integSessionId });
|
|
370
371
|
try {
|
|
371
372
|
await sh(env)(body.seedCmd);
|
|
372
373
|
await injectOracles(env);
|
|
@@ -412,7 +413,8 @@ export function createLeaderRunner(cfg) {
|
|
|
412
413
|
const resolveRepair = async (solo, _sub) => {
|
|
413
414
|
let env;
|
|
414
415
|
if (cfg.envFactory) {
|
|
415
|
-
|
|
416
|
+
const graderSessionId = `leader-grader-${Date.now()}`;
|
|
417
|
+
env = cfg.envFactory({ sessionId: graderSessionId, placementRootSessionId: graderSessionId });
|
|
416
418
|
}
|
|
417
419
|
else {
|
|
418
420
|
if (!cfg.e2bApiKey)
|