@sema-agent/server 7.141.0 → 7.143.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +657 -0
- package/USAGE.md +102 -30
- package/dist/adoption/plan.js +22 -0
- package/dist/approval-ask-audit-store.d.ts +61 -43
- package/dist/approval-ask-audit-store.js +69 -44
- package/dist/approval-ask-machine.d.ts +15 -7
- package/dist/approval-ask-machine.js +10 -4
- package/dist/approval-card.d.ts +126 -27
- package/dist/approval-card.js +103 -23
- package/dist/approval-crash-convergence.d.ts +17 -7
- package/dist/approval-crash-convergence.js +94 -22
- package/dist/approval-deny-reasons.d.ts +34 -30
- package/dist/approval-deny-reasons.js +21 -6
- package/dist/approval-policy-settlement.d.ts +1 -1
- package/dist/approval-queue-kind.d.ts +27 -0
- package/dist/approval-queue-kind.js +6 -0
- package/dist/approval-reconciler.d.ts +41 -9
- package/dist/approval-reconciler.js +45 -42
- package/dist/audit.js +4 -2
- package/dist/auth-bridge.d.ts +9 -6
- package/dist/auth-bridge.js +9 -3
- package/dist/boot/adoption.js +2 -1
- package/dist/boot/budget-tracing.d.ts +17 -1
- package/dist/boot/budget-tracing.js +10 -6
- package/dist/boot/device-lane.d.ts +1 -1
- package/dist/boot/execution-env.d.ts +24 -4
- package/dist/boot/execution-env.js +26 -23
- package/dist/boot/execution-lane.js +2 -1
- package/dist/boot/exit-boundary.js +5 -4
- package/dist/boot/governance-seams.d.ts +26 -41
- package/dist/boot/governance-seams.js +61 -28
- package/dist/boot/late-binds.d.ts +7 -4
- package/dist/boot/late-binds.js +3 -1
- package/dist/boot/leader.js +2 -4
- package/dist/boot/memory-consolidation.d.ts +0 -8
- package/dist/boot/memory-consolidation.js +5 -4
- package/dist/boot/parked-revive-gate.js +2 -1
- package/dist/boot/permission-rules-audit.d.ts +0 -28
- package/dist/boot/permission-rules-audit.js +2 -1
- package/dist/boot/read-deny-anchor-audit.js +2 -1
- package/dist/boot/reapers.js +9 -7
- package/dist/boot/resolve-spec.d.ts +1 -1
- package/dist/boot/resolve-spec.js +19 -10
- package/dist/boot/retention-lane.js +5 -3
- package/dist/boot/runner-deps.d.ts +10 -7
- package/dist/boot/runner-deps.js +20 -29
- package/dist/boot/runtime-caps.js +3 -2
- package/dist/boot/session-faces.js +4 -3
- package/dist/boot/shutdown.d.ts +9 -0
- package/dist/boot/shutdown.js +19 -4
- package/dist/boot/stage-02-web-admin-pull.js +3 -0
- package/dist/boot/stage-03-store-backend.d.ts +4 -1
- package/dist/boot/stage-03-store-backend.js +1 -2
- package/dist/boot/stage-04-stores.d.ts +5 -2
- package/dist/boot/stage-04-stores.js +6 -7
- package/dist/boot/stage-05-execution-env.d.ts +6 -3
- package/dist/boot/stage-05-execution-env.js +8 -6
- package/dist/boot/stage-06-runners.d.ts +6 -3
- package/dist/boot/stage-06-runners.js +3 -4
- package/dist/boot/stage-07-capability-layer.d.ts +6 -3
- package/dist/boot/stage-07-capability-layer.js +7 -2
- package/dist/boot/stage-08-reapers.d.ts +6 -3
- package/dist/boot/stage-08-reapers.js +3 -2
- package/dist/boot/stage-09-leader.d.ts +6 -3
- package/dist/boot/stage-10-http-server.d.ts +6 -3
- package/dist/boot/stage-10-http-server.js +14 -5
- package/dist/boot/stores.d.ts +5 -2
- package/dist/boot/stores.js +10 -9
- package/dist/boot/web-admin.d.ts +5 -1
- package/dist/boot/web-admin.js +48 -36
- package/dist/boot/webfetch-summarize-lane.js +2 -1
- package/dist/boot/workflow-orchestration.js +3 -2
- package/dist/capabilities/builtin-tools.d.ts +2 -1
- package/dist/capabilities/builtin-tools.js +2 -4
- package/dist/capabilities/composite-members.d.ts +2 -1
- package/dist/capabilities/composite-members.js +2 -1
- package/dist/capabilities/hands-lane.d.ts +9 -39
- package/dist/capabilities/hands-lane.js +8 -13
- package/dist/capabilities/mcp-probe.d.ts +3 -2
- package/dist/capabilities/scenarios.d.ts +11 -1
- package/dist/capabilities/scenarios.js +1 -0
- package/dist/capabilities/skills.d.ts +1 -17
- package/dist/capabilities/skills.js +0 -8
- package/dist/capability-facts.d.ts +31 -7
- package/dist/capability-facts.js +27 -4
- package/dist/card-void.d.ts +6 -9
- package/dist/config-catalog.js +2 -1
- package/dist/config-dir-trust.js +58 -29
- package/dist/config-invariants.d.ts +7 -1
- package/dist/config-invariants.js +7 -0
- package/dist/config-provider.d.ts +10 -0
- package/dist/config-provider.js +15 -4
- package/dist/config-root-migration.d.ts +13 -0
- package/dist/config-root-migration.js +99 -0
- package/dist/config-types.d.ts +19 -8
- package/dist/config.d.ts +10 -3
- package/dist/config.js +18 -4
- package/dist/delegated-session-owner.d.ts +5 -3
- package/dist/delegated-session-owner.js +1 -1
- package/dist/device-ws-protocol.d.ts +1 -0
- package/dist/device-ws-protocol.js +2 -1
- package/dist/env-model-table-gate.d.ts +53 -0
- package/dist/env-model-table-gate.js +53 -0
- package/dist/execution-lane-caps.d.ts +2 -1
- package/dist/fleet/fleet-bus.d.ts +34 -55
- package/dist/fleet/fleet-bus.js +35 -100
- package/dist/fleet/fleet-reconciler.d.ts +4 -4
- package/dist/fleet/fleet-reconciler.js +1 -1
- package/dist/fleet/subagent-tail-bus.d.ts +14 -11
- package/dist/fleet/subagent-tail-bus.js +15 -28
- package/dist/hooks/hook-runner.d.ts +6 -0
- package/dist/hooks/hook-runner.js +58 -8
- package/dist/host-decision.d.ts +54 -20
- package/dist/host-decision.js +42 -14
- package/dist/http/admission.d.ts +1 -1
- package/dist/http/admission.js +7 -3
- package/dist/http/approval-sweeps.js +11 -8
- package/dist/http/caller-trust.d.ts +1 -1
- package/dist/http/dispatch.js +4 -2
- package/dist/http/durable-run-leg.js +2 -2
- package/dist/http/engine-refusal.d.ts +16 -0
- package/dist/http/engine-refusal.js +17 -0
- package/dist/http/execution-context.d.ts +2 -2
- package/dist/http/idempotency.d.ts +1 -1
- package/dist/http/memory-compliance-failure-reply.d.ts +1 -3
- package/dist/http/memory-compliance-failure-reply.js +4 -6
- package/dist/http/owner-access.d.ts +11 -0
- package/dist/http/owner-access.js +13 -0
- package/dist/http/principal-gate.d.ts +3 -1
- package/dist/http/principal-gate.js +17 -8
- package/dist/http/resume-legs.d.ts +21 -7
- package/dist/http/resume-legs.js +76 -58
- package/dist/http/resume-restatement.d.ts +39 -0
- package/dist/http/resume-restatement.js +25 -0
- package/dist/http/route-ctx.d.ts +35 -10
- package/dist/http/route-ctx.js +1 -1
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/approvals-assistant.d.ts +9 -1
- package/dist/http/routes/approvals-assistant.js +142 -31
- package/dist/http/routes/attachments.js +18 -0
- package/dist/http/routes/capabilities.js +16 -4
- package/dist/http/routes/memory-policy.d.ts +2 -2
- package/dist/http/routes/memory-policy.js +27 -7
- package/dist/http/routes/notify-wake.js +23 -25
- package/dist/http/routes/rules.js +48 -13
- package/dist/http/routes/runs.js +12 -11
- package/dist/http/routes/session-memory-sync.d.ts +91 -0
- package/dist/http/routes/session-memory-sync.js +174 -0
- package/dist/http/routes/session-sync.js +13 -20
- package/dist/http/routes/sessions-list.d.ts +2 -1
- package/dist/http/routes/sessions.d.ts +2 -2
- package/dist/http/routes/sessions.js +22 -23
- package/dist/http/routes/tasks.js +34 -54
- package/dist/http/run-read-face.d.ts +7 -0
- package/dist/http/run-read-face.js +9 -3
- package/dist/http/send.d.ts +5 -0
- package/dist/http/send.js +9 -2
- package/dist/http/server.d.ts +27 -15
- package/dist/http/server.js +4 -6
- package/dist/http/stored-body-replay.js +15 -4
- package/dist/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +2 -2
- package/dist/http/sync-submit-body.d.ts +21 -4
- package/dist/http/sync-submit-body.js +13 -0
- package/dist/http/wire-types.d.ts +17 -7
- package/dist/identity-source.d.ts +21 -2
- package/dist/identity-source.js +6 -0
- package/dist/leader/leader.js +5 -2
- package/dist/leader/wire.d.ts +7 -1
- package/dist/leader/wire.js +6 -5
- package/dist/leg-facts.d.ts +37 -0
- package/dist/leg-facts.js +15 -0
- package/dist/memory-bundle-engine.d.ts +1 -4
- package/dist/memory-bundle-engine.js +2 -2
- package/dist/memory-incident-sink.d.ts +19 -6
- package/dist/memory-incident-sink.js +8 -4
- package/dist/memory-operator-faces.d.ts +30 -66
- package/dist/memory-operator-faces.js +17 -88
- package/dist/memory-scope-stores.d.ts +38 -40
- package/dist/memory-scope-stores.js +51 -36
- package/dist/memory-scope.d.ts +0 -9
- package/dist/memory-scope.js +0 -9
- package/dist/memory-sync-client.d.ts +21 -21
- package/dist/memory-sync-client.js +62 -43
- package/dist/memory-sync-identity.d.ts +24 -0
- package/dist/memory-sync-identity.js +57 -0
- package/dist/memory-sync.d.ts +27 -5
- package/dist/memory-sync.js +29 -7
- package/dist/model-plane-face.d.ts +13 -7
- package/dist/model-plane-face.js +2 -1
- package/dist/observability/fail-open.d.ts +47 -14
- package/dist/observability/fail-open.js +37 -11
- package/dist/observability/run-terminal.d.ts +92 -34
- package/dist/observability/run-terminal.js +171 -162
- package/dist/orchestration/workflow-completion-inbox.d.ts +5 -19
- package/dist/orchestration/workflow-completion-inbox.js +0 -12
- package/dist/orchestration/workflow-notify-journal.d.ts +3 -2
- package/dist/orchestration/workflow-park-decision.d.ts +8 -3
- package/dist/orchestration/workflow-park-decision.js +5 -3
- package/dist/org-delivery-gate.d.ts +11 -0
- package/dist/org-delivery-gate.js +19 -1
- package/dist/parked-decide.d.ts +13 -9
- package/dist/parked-decide.js +7 -7
- package/dist/parked-revive-surface.js +1 -1
- package/dist/peer-inbound-face.d.ts +127 -0
- package/dist/peer-inbound-face.js +158 -0
- package/dist/permission-rule-list.d.ts +13 -9
- package/dist/permission-rule-list.js +7 -3
- package/dist/plugins/approval-ask-store-file.d.ts +14 -4
- package/dist/plugins/approval-ask-store-file.js +64 -11
- package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
- package/dist/plugins/approval-ask-store-memory.js +17 -14
- package/dist/plugins/approval-ask-store-sql.d.ts +70 -23
- package/dist/plugins/approval-ask-store-sql.js +79 -30
- package/dist/plugins/checkpoint-store-sql.d.ts +4 -4
- package/dist/plugins/checkpoint-store-sql.js +9 -7
- package/dist/plugins/file-history-store-sql.d.ts +24 -18
- package/dist/plugins/file-history-store-sql.js +24 -19
- package/dist/plugins/file-run-store.d.ts +35 -1
- package/dist/plugins/file-run-store.js +108 -9
- package/dist/plugins/imported-layer-root-retirement.d.ts +82 -0
- package/dist/plugins/imported-layer-root-retirement.js +96 -0
- package/dist/plugins/local-checkpoint-store.d.ts +1 -1
- package/dist/plugins/local-checkpoint-store.js +2 -2
- package/dist/plugins/local-session-store.d.ts +42 -9
- package/dist/plugins/local-session-store.js +83 -33
- package/dist/plugins/local-task-attachment-store.d.ts +12 -2
- package/dist/plugins/local-task-attachment-store.js +67 -43
- package/dist/plugins/mailbox-recipient-lifecycle.d.ts +9 -31
- package/dist/plugins/mailbox-recipient-lifecycle.js +4 -0
- package/dist/plugins/mailbox-store-sql.d.ts +12 -8
- package/dist/plugins/mailbox-store-sql.js +76 -7
- package/dist/plugins/memory-key-guards.d.ts +3 -3
- package/dist/plugins/memory-run-store.d.ts +6 -1
- package/dist/plugins/memory-run-store.js +11 -1
- package/dist/plugins/memory-sync-store-pg.d.ts +15 -0
- package/dist/plugins/memory-sync-store-pg.js +21 -0
- package/dist/plugins/memory-sync-store-tidb.d.ts +2 -0
- package/dist/plugins/memory-sync-store-tidb.js +13 -1
- package/dist/plugins/one-time-migrations.d.ts +58 -2
- package/dist/plugins/one-time-migrations.js +161 -4
- package/dist/plugins/org-delivery-quota-store.d.ts +1 -1
- package/dist/plugins/org-delivery-quota-store.js +2 -12
- package/dist/plugins/park-commit-watch.d.ts +1 -1
- package/dist/plugins/permission-rule-store-file.d.ts +10 -1
- package/dist/plugins/permission-rule-store-file.js +15 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +31 -1
- package/dist/plugins/permission-rule-store-sql.js +35 -2
- package/dist/plugins/remote-env-device.d.ts +8 -11
- package/dist/plugins/remote-env-device.js +6 -3
- package/dist/plugins/remote-env-e2b.d.ts +23 -4
- package/dist/plugins/remote-env-e2b.js +111 -28
- package/dist/plugins/remote-env-k8s.d.ts +61 -22
- package/dist/plugins/remote-env-k8s.js +133 -33
- package/dist/plugins/remote-env-local-docker.d.ts +15 -3
- package/dist/plugins/remote-env-local-docker.js +40 -12
- package/dist/plugins/retention-store-sql.d.ts +2 -2
- package/dist/plugins/run-store-sql.d.ts +9 -1
- package/dist/plugins/run-store-sql.js +9 -1
- package/dist/plugins/sandbox-read-floor.d.ts +5 -7
- package/dist/plugins/sandbox-read-floor.js +2 -7
- package/dist/plugins/sql-errors.d.ts +10 -1
- package/dist/plugins/sql-errors.js +13 -0
- package/dist/plugins/store-backend.d.ts +33 -35
- package/dist/plugins/store-backend.js +10 -1
- package/dist/plugins/store-contracts.d.ts +50 -1
- package/dist/plugins/store-contracts.js +6 -0
- package/dist/plugins/task-attachment-store.d.ts +112 -14
- package/dist/plugins/task-attachment-store.js +207 -29
- package/dist/plugins/tool-result-store-sql.d.ts +9 -8
- package/dist/plugins/tool-result-store-sql.js +23 -2
- package/dist/plugins/wiring-section-codec.d.ts +32 -0
- package/dist/plugins/wiring-section-codec.js +55 -0
- package/dist/plugins/workspace-fill.d.ts +60 -0
- package/dist/plugins/workspace-fill.js +106 -0
- package/dist/project-bundle.d.ts +38 -0
- package/dist/project-bundle.js +609 -0
- package/dist/rule-entry-list.d.ts +3 -2
- package/dist/rule-entry-list.js +5 -1
- package/dist/rules-consent.d.ts +28 -5
- package/dist/rules-consent.js +40 -28
- package/dist/run-local.js +11 -13
- package/dist/runs.d.ts +12 -8
- package/dist/runs.js +6 -8
- package/dist/runtime-governance.d.ts +1 -1
- package/dist/sandbox-egress-policy.d.ts +4 -1
- package/dist/sandbox-egress-policy.js +3 -1
- package/dist/sandbox-git-plane.d.ts +31 -12
- package/dist/sandbox-git-plane.js +24 -4
- package/dist/security.d.ts +9 -0
- package/dist/security.js +8 -0
- package/dist/server-secret-env.d.ts +4 -0
- package/dist/session-error-wire.d.ts +36 -0
- package/dist/session-error-wire.js +13 -0
- package/dist/session-incarnation.d.ts +1 -1
- package/dist/session-notify-door.d.ts +106 -0
- package/dist/session-notify-door.js +93 -0
- package/dist/session-sync.d.ts +9 -14
- package/dist/session-sync.js +5 -5
- package/dist/session-workspace.d.ts +3 -13
- package/dist/session-workspace.js +0 -9
- package/dist/standing-answer-grant.d.ts +5 -0
- package/dist/standing-answer-grant.js +10 -0
- package/dist/stores-sql/session-policy-store-sql.d.ts +4 -2
- package/dist/stores-sql/session-policy-store-sql.js +3 -13
- package/dist/task-mcp.d.ts +1 -1
- package/dist/task-settings.d.ts +21 -10
- package/dist/task-settings.js +46 -13
- package/dist/terminal.d.ts +39 -19
- package/dist/terminal.js +65 -22
- package/dist/tool-approval.d.ts +56 -37
- package/dist/tool-approval.js +78 -71
- package/dist/trace/core-keyset-guard.d.ts +134 -14
- package/dist/trace/engine-notice-wire.d.ts +9 -3
- package/dist/trace/engine-notice-wire.js +7 -3
- package/dist/trace/exit-seat.d.ts +9 -2
- package/dist/trace/exit-seat.js +1 -0
- package/dist/trace/ledger-sink.d.ts +10 -6
- package/dist/trace/ledger-sink.js +2 -2
- package/dist/trace/model-segment.d.ts +55 -25
- package/dist/trace/model-segment.js +101 -33
- package/dist/trace/project.d.ts +25 -5
- package/dist/trace/project.js +22 -0
- package/dist/trace/redact.d.ts +61 -9
- package/dist/trace/redact.js +1490 -468
- package/dist/trace/self-minted-wire.d.ts +745 -24
- package/dist/trace/self-minted-wire.js +239 -9
- package/dist/trace/wire-projection-faces.d.ts +2 -2
- package/dist/trace/wire-projection-faces.js +2 -2
- package/dist/verifier-pause-card.d.ts +33 -5
- package/dist/verifier-pause-card.js +15 -10
- package/dist/web-admin-client/apply-effective.d.ts +12 -16
- package/dist/web-admin-client/apply-effective.js +109 -9
- package/dist/web-admin-client/effective-keys.js +2 -0
- package/dist/web-admin-client/types.d.ts +4 -0
- package/dist/workspace-space.d.ts +19 -3
- package/dist/workspace-space.js +8 -4
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -1
- package/package.json +3 -2
- package/wire-changes/server@7.142.0.json +639 -0
- package/wire-changes/server@7.143.0.json +1167 -0
|
@@ -21,7 +21,7 @@ function withDeadline(op, label, timeoutMs = RECONCILE_STORE_TIMEOUT_MS) {
|
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
23
|
export function isAncestorFoldMint(ask) {
|
|
24
|
-
return ask.parentToolCallId === null && ask.
|
|
24
|
+
return ask.parentToolCallId === null && ask.sourceSessionId !== ask.sessionId;
|
|
25
25
|
}
|
|
26
26
|
export function classifyGateMatch(ask, candidates) {
|
|
27
27
|
const outcome = classifyGateMatchBeforeFoldVeto(ask, candidates);
|
|
@@ -30,7 +30,7 @@ export function classifyGateMatch(ask, candidates) {
|
|
|
30
30
|
return outcome;
|
|
31
31
|
}
|
|
32
32
|
function classifyGateMatchBeforeFoldVeto(ask, candidates) {
|
|
33
|
-
const sameIdentity = candidates.filter((c) => c.unparseable !== true && c.
|
|
33
|
+
const sameIdentity = candidates.filter((c) => c.unparseable !== true && c.sourceSessionId !== null && c.sourceSessionId === ask.sourceSessionId && c.boundCallId === ask.toolCallId && c.createdAtMs >= ask.createdAtMs);
|
|
34
34
|
const askHash = ask.boundInputHash;
|
|
35
35
|
if (sameIdentity.length === 0) {
|
|
36
36
|
if (candidates.length > 0)
|
|
@@ -79,6 +79,45 @@ export function decideReconcileAction(input) {
|
|
|
79
79
|
void candidates;
|
|
80
80
|
return { kind: "hold" };
|
|
81
81
|
}
|
|
82
|
+
export async function bindParkingAskAtGate(deps, ask, nowMs, deadlineMs) {
|
|
83
|
+
const { askStore, checkpoints, warn, revoke } = deps;
|
|
84
|
+
const expired = () => deadlineMs !== undefined && Date.now() >= deadlineMs;
|
|
85
|
+
const batchRow = await withDeadline(askStore.getBatch(ask.batchId), "getBatch");
|
|
86
|
+
let batchState = batchRow?.state ?? "MISSING";
|
|
87
|
+
let batchBoundAskId = batchRow?.boundAskId ?? null;
|
|
88
|
+
const irreversibleBatch = batchState === "ABORTED" || (batchState === "ROUTING_BOUND" && batchBoundAskId !== null && batchBoundAskId !== ask.askId);
|
|
89
|
+
let gateMatch;
|
|
90
|
+
if (checkpoints && !irreversibleBatch && !expired()) {
|
|
91
|
+
const candidates = await withDeadline(checkpoints.findCheckpointCandidatesForAsk(encodeCheckpointScope(ask.owner), ask.sessionId, ask.toolCallId, ask.createdAtMs), "findCheckpointCandidatesForAsk");
|
|
92
|
+
gateMatch = classifyGateMatch(ask, candidates);
|
|
93
|
+
if (gateMatch.kind === "hash_mismatch") {
|
|
94
|
+
warn("approval_reconcile_hash_mismatch", {
|
|
95
|
+
askId: ask.askId,
|
|
96
|
+
taskId: ask.taskId,
|
|
97
|
+
toolCallId: ask.toolCallId,
|
|
98
|
+
candidates: gateMatch.candidates,
|
|
99
|
+
reason: "ask and checkpoint minted the same bound input under the same (sourceSessionId, toolCallId) identity but the digests differ — " +
|
|
100
|
+
"the known causes are deployment-side (a hook/policy mutating an object it still holds a reference to between the two mints, " +
|
|
101
|
+
"or a stateful getter returning a fresh value per read), not out-of-band interference; this ask keeps its fail-safe route (no park, no denial)",
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
const match = gateMatch.kind === "match" ? gateMatch.candidate : undefined;
|
|
105
|
+
if (match && !expired()) {
|
|
106
|
+
const res = await withDeadline(askStore.bindBatch(ask.batchId, ask.askId, {
|
|
107
|
+
gateToken: match.token,
|
|
108
|
+
gateBoundCallId: match.boundCallId,
|
|
109
|
+
gateBoundInputHash: match.boundInputHash,
|
|
110
|
+
}), "bindBatch");
|
|
111
|
+
if (res.ok) {
|
|
112
|
+
revoke(ask, res.voidedSiblings, "superseded_by_park", nowMs);
|
|
113
|
+
return { bound: true, match: gateMatch };
|
|
114
|
+
}
|
|
115
|
+
batchState = res.batchState;
|
|
116
|
+
batchBoundAskId = res.boundAskId ?? null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return { bound: false, ...(gateMatch !== undefined ? { match: gateMatch } : {}), batchState, batchBoundAskId, irreversibleBatch };
|
|
120
|
+
}
|
|
82
121
|
export function createApprovalReconciler(deps) {
|
|
83
122
|
const { askStore, checkpoints, runs, logger, metrics, batchLimit, pendingGraceMs, adhocGraceMs, orphanTtlMs, unattendedPolicy, emitRevoke } = deps;
|
|
84
123
|
const warn = (event, fields) => {
|
|
@@ -98,44 +137,8 @@ export function createApprovalReconciler(deps) {
|
|
|
98
137
|
warn("approval_revoke_emit_failed", { batchId: row.batchId, count: askIds.length, err: err instanceof Error ? err.message : String(err) });
|
|
99
138
|
}
|
|
100
139
|
};
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
const batchRow = await withDeadline(askStore.getBatch(ask.batchId), "getBatch");
|
|
104
|
-
let batchState = batchRow?.state ?? "MISSING";
|
|
105
|
-
let batchBoundAskId = batchRow?.boundAskId ?? null;
|
|
106
|
-
const irreversibleBatch = batchState === "ABORTED" || (batchState === "ROUTING_BOUND" && batchBoundAskId !== null && batchBoundAskId !== ask.askId);
|
|
107
|
-
let gateMatch;
|
|
108
|
-
if (checkpoints && !irreversibleBatch && !expired()) {
|
|
109
|
-
const candidates = await withDeadline(checkpoints.findCheckpointCandidatesForAsk(encodeCheckpointScope(ask.owner), ask.sessionId, ask.toolCallId, ask.createdAtMs), "findCheckpointCandidatesForAsk");
|
|
110
|
-
gateMatch = classifyGateMatch(ask, candidates);
|
|
111
|
-
if (gateMatch.kind === "hash_mismatch") {
|
|
112
|
-
warn("approval_reconcile_hash_mismatch", {
|
|
113
|
-
askId: ask.askId,
|
|
114
|
-
taskId: ask.taskId,
|
|
115
|
-
toolCallId: ask.toolCallId,
|
|
116
|
-
candidates: gateMatch.candidates,
|
|
117
|
-
reason: "ask and checkpoint minted the same bound input under the same (sourceTaskId, toolCallId) identity but the digests differ — " +
|
|
118
|
-
"the known causes are deployment-side (a hook/policy mutating an object it still holds a reference to between the two mints, " +
|
|
119
|
-
"or a stateful getter returning a fresh value per read), not out-of-band interference; this ask keeps its fail-safe route (no park, no denial)",
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
const match = gateMatch.kind === "match" ? gateMatch.candidate : undefined;
|
|
123
|
-
if (match && !expired()) {
|
|
124
|
-
const res = await withDeadline(askStore.bindBatch(ask.batchId, ask.askId, {
|
|
125
|
-
gateToken: match.token,
|
|
126
|
-
gateBoundCallId: match.boundCallId,
|
|
127
|
-
gateBoundInputHash: match.boundInputHash,
|
|
128
|
-
}), "bindBatch");
|
|
129
|
-
if (res.ok) {
|
|
130
|
-
revoke(ask, res.voidedSiblings, "superseded_by_park", nowMs);
|
|
131
|
-
return { bound: true, match: gateMatch };
|
|
132
|
-
}
|
|
133
|
-
batchState = res.batchState;
|
|
134
|
-
batchBoundAskId = res.boundAskId ?? null;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return { bound: false, ...(gateMatch !== undefined ? { match: gateMatch } : {}), batchState, batchBoundAskId, irreversibleBatch };
|
|
138
|
-
};
|
|
140
|
+
const gate = { askStore, checkpoints, warn, revoke };
|
|
141
|
+
const bindAtGate = (ask, nowMs, deadlineMs) => bindParkingAskAtGate(gate, ask, nowMs, deadlineMs);
|
|
139
142
|
const reconcileOne = async (ask, nowMs) => {
|
|
140
143
|
const attempt = await bindAtGate(ask, nowMs);
|
|
141
144
|
if (attempt.bound)
|
|
@@ -150,11 +153,11 @@ export function createApprovalReconciler(deps) {
|
|
|
150
153
|
return { outcome: "held", match: gateMatch };
|
|
151
154
|
}
|
|
152
155
|
case "deny": {
|
|
153
|
-
const won = await withDeadline(askStore.transitionAsk(ask.askId, "PARKING", "DENIED", {
|
|
156
|
+
const won = await withDeadline(askStore.transitionAsk(ask.askId, "PARKING", "DENIED", { endingCause: action.reason, updatedAtMs: nowMs }), "transitionAsk(DENIED)");
|
|
154
157
|
return { outcome: won ? "denied" : "held", match: gateMatch };
|
|
155
158
|
}
|
|
156
159
|
case "void": {
|
|
157
|
-
const won = await withDeadline(askStore.transitionAsk(ask.askId, "PARKING", "VOID", {
|
|
160
|
+
const won = await withDeadline(askStore.transitionAsk(ask.askId, "PARKING", "VOID", { endingCause: action.reason, updatedAtMs: nowMs }), "transitionAsk(VOID)");
|
|
158
161
|
if (!won)
|
|
159
162
|
return { outcome: "held", match: gateMatch };
|
|
160
163
|
if (action.reason === APPROVAL_ENDING_CAUSES.ORPHAN_TTL_EXCEEDED) {
|
package/dist/audit.js
CHANGED
|
@@ -129,8 +129,9 @@ const MESSAGE_READ_TREATMENT = {
|
|
|
129
129
|
runOrigin: "verbatim",
|
|
130
130
|
taskId: "verbatim",
|
|
131
131
|
attachment: "verbatim",
|
|
132
|
+
rewrittenBy: "verbatim",
|
|
132
133
|
},
|
|
133
|
-
custom: { role: "verbatim", customType: "verbatim", content: "verbatim", display: "verbatim", details: "verbatim", provenance: "verbatim", timestamp: "verbatim" },
|
|
134
|
+
custom: { role: "verbatim", customType: "verbatim", content: "verbatim", display: "verbatim", details: "verbatim", provenance: "verbatim", timestamp: "verbatim", rewrittenBy: "verbatim" },
|
|
134
135
|
assistant: {
|
|
135
136
|
role: "verbatim", content: "parts", errorMessage: "text", diagnostics: "structure", repetition: "structure",
|
|
136
137
|
api: "verbatim", provider: "verbatim", model: "verbatim", responseModel: "verbatim", responseId: "verbatim", requestId: "verbatim",
|
|
@@ -139,8 +140,9 @@ const MESSAGE_READ_TREATMENT = {
|
|
|
139
140
|
staticReasoningCut: "verbatim", timestamp: "verbatim",
|
|
140
141
|
providerCondition: "verbatim", providerConditionSource: "verbatim", providerResetAtMs: "verbatim", apiErrorRoute: "verbatim",
|
|
141
142
|
errorBodyIncomplete: "verbatim", modelOutputInvalid: "verbatim", finishReasonUnknown: "verbatim", streamEndIgnored: "verbatim",
|
|
143
|
+
refusedTool: "verbatim", rewrittenBy: "verbatim",
|
|
142
144
|
},
|
|
143
|
-
toolResult: { role: "verbatim", toolCallId: "verbatim", toolName: "verbatim", content: "parts", details: "toolCard", isError: "verbatim", timestamp: "verbatim" },
|
|
145
|
+
toolResult: { role: "verbatim", toolCallId: "verbatim", toolName: "verbatim", content: "parts", details: "toolCard", isError: "verbatim", timestamp: "verbatim", rewrittenBy: "verbatim" },
|
|
144
146
|
bashExecution: {
|
|
145
147
|
role: "verbatim", command: "text", output: "text", exitCode: "verbatim", cancelled: "verbatim", truncated: "verbatim",
|
|
146
148
|
fullOutputPath: "verbatim", timestamp: "verbatim", excludeFromContext: "verbatim",
|
package/dist/auth-bridge.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { VerifiedIdentity, type AuthBridgeErrorCode } from "@sema-agent/settings-schema/api/auth-bridge";
|
|
2
2
|
import { type TokenScopeRefusal } from "@sema-agent/settings-schema/api/scopes";
|
|
3
3
|
import type { Logger } from "./observability/logger.js";
|
|
4
4
|
import type { Metrics } from "./observability/metrics.js";
|
|
@@ -52,12 +52,13 @@ type BridgeSinks = {
|
|
|
52
52
|
readonly logger?: Logger | undefined;
|
|
53
53
|
readonly metrics?: Pick<Metrics, "inc"> | undefined;
|
|
54
54
|
};
|
|
55
|
-
/** 注入边界收的结局:与 {@link VerifyOutcome} 同形,只是成功身份的 `scope` 是 `unknown` ——
|
|
56
|
-
* (席是嵌入方可换的:`""` 过得了 `scope: string`,JS 侧连缺省 / 非串都交得进来)。`VerifyOutcome` 可赋给它,调用方零改动。 */
|
|
55
|
+
/** 注入边界收的结局:与 {@link VerifyOutcome} 同形,只是成功身份的 `scope` 与 `principalInc` 是 `unknown` —— 这两位正是边界要判的形,它不信型面
|
|
56
|
+
* (席是嵌入方可换的:`""` 过得了 `scope: string` / `principalInc?: string`,JS 侧连缺省 / 非串都交得进来)。`VerifyOutcome` 可赋给它,调用方零改动。 */
|
|
57
57
|
type ReportedOutcome = {
|
|
58
58
|
ok: true;
|
|
59
|
-
identity: Omit<BridgeIdentity, "scope"> & {
|
|
59
|
+
identity: Omit<BridgeIdentity, "scope" | "principalInc"> & {
|
|
60
60
|
scope?: unknown;
|
|
61
|
+
principalInc?: unknown;
|
|
61
62
|
};
|
|
62
63
|
} | {
|
|
63
64
|
ok: false;
|
|
@@ -65,8 +66,10 @@ type ReportedOutcome = {
|
|
|
65
66
|
};
|
|
66
67
|
/**
|
|
67
68
|
* 注入边界:任何验证器(内建 {@link createWebAdminJwtVerifier},或嵌入方注入的 `ServiceDeps.webAdminJwtVerifier`)交来的结局,在这里定「装不装身份」。
|
|
68
|
-
* 成功身份的 scope 经**同一只** `readTokenScope`
|
|
69
|
-
*
|
|
69
|
+
* 成功身份的 scope 经**同一只** `readTokenScope` 再读一次;化身号经契约的**同一只**判官 `VerifiedIdentity.shape.principalInc`(= `PrincipalIncarnation.optional()`,
|
|
70
|
+
* 契约验证器读 `sub_inc` 用的就是它)再判一次(入参型见 {@link ReportedOutcome})。
|
|
71
|
+
* 读不出 scope ⇒ 记 `readTokenScope` 的拒词;化身号在场而不合形 ⇒ 记 `malformed`(与契约验证器同一条律:声明在场坏形 ⇒ 令牌 malformed)。两种都经同一只记账口、不交身份
|
|
72
|
+
* (调用方按验证失败处置:不设身份 ⇒ 门答 generic 401)。验证失败的结局验证器自己已记过账,这里只答「不装」。
|
|
70
73
|
*/
|
|
71
74
|
export declare function admitBridgeIdentity(outcome: ReportedOutcome, sinks: BridgeSinks): BridgeIdentity | undefined;
|
|
72
75
|
/** The live object `createWebAdminJwtVerifier` produces — a single `verify` entry point over the process-level JWKS cache. */
|
package/dist/auth-bridge.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createPublicKey, verify as cryptoVerify } from "node:crypto";
|
|
2
|
-
import { AUTH_BRIDGE_ALGS, DEFAULT_CLOCK_SKEW_SEC, DEFAULT_JWKS_REFRESH_MIN_INTERVAL_SEC, DEFAULT_OFFLINE_GRACE_SEC, WEB_ADMIN_JWKS_PATH, WebAdminJwks, classifyTimeClaims, jwksWithinOfflineGrace, shouldForceJwksRefresh, toVerifiedIdentity, } from "@sema-agent/settings-schema/api/auth-bridge";
|
|
2
|
+
import { AUTH_BRIDGE_ALGS, DEFAULT_CLOCK_SKEW_SEC, DEFAULT_JWKS_REFRESH_MIN_INTERVAL_SEC, DEFAULT_OFFLINE_GRACE_SEC, WEB_ADMIN_JWKS_PATH, WebAdminJwks, classifyTimeClaims, jwksWithinOfflineGrace, shouldForceJwksRefresh, toVerifiedIdentity, VerifiedIdentity, } from "@sema-agent/settings-schema/api/auth-bridge";
|
|
3
3
|
import { readTokenScope } from "@sema-agent/settings-schema/api/scopes";
|
|
4
4
|
import { buildDisplaySafeUrl } from "./trace/redact.js";
|
|
5
5
|
import { centerJwksFetch } from "./web-admin-client/center-request.js";
|
|
@@ -17,12 +17,18 @@ function recordBridgeRefusal(sinks, error, at = {}) {
|
|
|
17
17
|
export function admitBridgeIdentity(outcome, sinks) {
|
|
18
18
|
if (!outcome.ok)
|
|
19
19
|
return undefined;
|
|
20
|
-
const
|
|
20
|
+
const { scope, principalInc, ...rest } = outcome.identity;
|
|
21
|
+
const scoped = readTokenScope({ scope });
|
|
21
22
|
if ("refused" in scoped) {
|
|
22
23
|
recordBridgeRefusal(sinks, scoped.refused);
|
|
23
24
|
return undefined;
|
|
24
25
|
}
|
|
25
|
-
|
|
26
|
+
const inc = VerifiedIdentity.shape.principalInc.safeParse(principalInc);
|
|
27
|
+
if (!inc.success) {
|
|
28
|
+
recordBridgeRefusal(sinks, "malformed");
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
return { ...rest, scope: scoped.scope, ...(inc.data !== undefined ? { principalInc: inc.data } : {}) };
|
|
26
32
|
}
|
|
27
33
|
export const DEFAULT_JWKS_TTL_SEC = 15 * 60;
|
|
28
34
|
export const JWKS_FETCH_TIMEOUT_MS = 10_000;
|
package/dist/boot/adoption.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createAdoptionRunner } from "../adoption/runner.js";
|
|
2
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
2
3
|
export async function runAdoptionBootScan(ctx) {
|
|
3
4
|
const store = ctx.backend?.adoptionLog?.();
|
|
4
5
|
if (!store)
|
|
@@ -29,7 +30,7 @@ export async function runAdoptionBootScan(ctx) {
|
|
|
29
30
|
return reading;
|
|
30
31
|
}
|
|
31
32
|
catch (err) {
|
|
32
|
-
const error = err instanceof Error ? err.message : String(err);
|
|
33
|
+
const error = seatText("operator-log-text", err instanceof Error ? err.message : String(err));
|
|
33
34
|
ctx.logger.error?.("adoption_boot_scan_failed", { error });
|
|
34
35
|
return { scanned: 0, resumed: [], stalled: [], rejected: [], failed: [], error };
|
|
35
36
|
}
|
|
@@ -11,6 +11,22 @@ export interface BudgetTracingCtx {
|
|
|
11
11
|
backend: StoreBackend | undefined;
|
|
12
12
|
breakerState: ReturnType<BreakerStateStore["startRefresh"]> | undefined;
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* S9 (SILENT-FALLBACK P0-e): write-behind flush/refresh failures previously vanished in a bare catch —
|
|
16
|
+
* the fleet silently degrades to per-replica counting (soft limits stop being fleet-wide). Every failure
|
|
17
|
+
* ticks the counter + streak gauge; warn once per episode (streak hits 3), info on the recovery edge.
|
|
18
|
+
* `info.error` is the client exception's text (the counter turns the rejection into it) ⇒ the warn's field passes the exit seat.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createCounterDegradeHook({ logger, metrics }: {
|
|
21
|
+
logger: Pick<Logger, "warn" | "info">;
|
|
22
|
+
metrics: Pick<Metrics, "setGauge" | "inc">;
|
|
23
|
+
}): (info: {
|
|
24
|
+
table: string;
|
|
25
|
+
kind: string;
|
|
26
|
+
streak: number;
|
|
27
|
+
prevStreak: number;
|
|
28
|
+
error?: string;
|
|
29
|
+
}) => void;
|
|
14
30
|
export declare function createBudgetAndTracing(ctx: BudgetTracingCtx): {
|
|
15
31
|
brain: import("@sema-agent/core").Brain;
|
|
16
32
|
degradeRouteWatch: import("../brain.js").DegradeRouteWatch;
|
|
@@ -29,7 +45,7 @@ export declare function createBudgetAndTracing(ctx: BudgetTracingCtx): {
|
|
|
29
45
|
fleetLease: import("../fleet-lease.js").FleetLeaseManager | undefined;
|
|
30
46
|
tracer: import("@sema-agent/core").TracerHook;
|
|
31
47
|
sideQueryAccounting: import("../budget.js").SideQueryAccounting;
|
|
32
|
-
toolResultStore: import("
|
|
48
|
+
toolResultStore: import("@sema-agent/core").ToolResultStore | undefined;
|
|
33
49
|
sessionPolicyStore: import("@sema-agent/core").SessionPolicyStore | undefined;
|
|
34
50
|
fileHistoryStore: import("../plugins/store-backend.js").ServiceFileHistoryStore | undefined;
|
|
35
51
|
fileHistoryErasure: import("../file-history-capture.js").FileHistoryErasureFace | undefined;
|
|
@@ -6,19 +6,23 @@ import { centerLaneConfigured } from "../web-admin-client/center-request.js";
|
|
|
6
6
|
import { CostQuota } from "../observability/cost-quota.js";
|
|
7
7
|
import { buildQuotaBounds } from "./limit-sync.js";
|
|
8
8
|
import { assembleFileHistory } from "../file-history-capture.js";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const pricing = buildPricing(config.models);
|
|
13
|
-
const counterDegradeHook = (info) => {
|
|
9
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
10
|
+
export function createCounterDegradeHook({ logger, metrics }) {
|
|
11
|
+
return (info) => {
|
|
14
12
|
metrics.setGauge("counter_flush_fail_streak", info.streak, { table: info.table, kind: info.kind });
|
|
15
13
|
if (info.streak > 0)
|
|
16
14
|
metrics.inc("counter_flush_failed_total", { table: info.table, kind: info.kind });
|
|
17
15
|
if (info.streak === 3)
|
|
18
|
-
logger.warn("counter_flush_degraded", { table: info.table, kind: info.kind, streak: info.streak, ...(info.error ? { error: info.error } : {}) });
|
|
16
|
+
logger.warn("counter_flush_degraded", { table: info.table, kind: info.kind, streak: info.streak, ...(info.error ? { error: seatText("operator-log-text", info.error) } : {}) });
|
|
19
17
|
else if (info.streak === 0 && info.prevStreak >= 3)
|
|
20
18
|
logger.info("counter_flush_recovered", { table: info.table, kind: info.kind, prevStreak: info.prevStreak });
|
|
21
19
|
};
|
|
20
|
+
}
|
|
21
|
+
export function createBudgetAndTracing(ctx) {
|
|
22
|
+
const { config, logger, metrics, backend, breakerState } = ctx;
|
|
23
|
+
const { brain, degradeRoute: degradeRouteWatch } = createBrainAssembly(config, { breakerState });
|
|
24
|
+
const pricing = buildPricing(config.models);
|
|
25
|
+
const counterDegradeHook = createCounterDegradeHook({ logger, metrics });
|
|
22
26
|
const bounds = buildQuotaBounds(config);
|
|
23
27
|
const costQuota = backend?.costQuota
|
|
24
28
|
? backend.costQuota(bounds.limitMicroUsd, bounds.windowMs, counterDegradeHook).startRefresh()
|
|
@@ -77,7 +77,7 @@ export declare function createDeviceLane(ctx: DeviceLaneCtx): DeviceLane | undef
|
|
|
77
77
|
*/
|
|
78
78
|
export declare function assertDeviceLaneWired(isDeviceLane: boolean, lane: DeviceLane | undefined, hasFactory: boolean): void;
|
|
79
79
|
/**
|
|
80
|
-
* 设备入口 × 已绑设备的起服一行(拒的那一半在配置期:device 车道上 `DEVICE_RELAY_URL`
|
|
80
|
+
* 设备入口 × 已绑设备的起服一行(拒的那一半在配置期:device 车道上 `DEVICE_RELAY_URL` 必填 —— 缺席拒起是车道必需 env 门(`config.ts` `declaredExecutionLane` → `laneMissingEnv`),坏形 / 带凭据形拒启是 `parseDeviceRelayUrlEnv`;
|
|
81
81
|
* 起不起服不随表里有几条绑定变)。
|
|
82
82
|
*
|
|
83
83
|
* 字面 `none` = 运维声明「设备拨本引擎自己的地址 + `wsPath`」。此刻根会话行上若有设备绑定(writer(device, D) 的格),这些会话的设备从此只能拨那个入口 ——
|
|
@@ -8,10 +8,13 @@ import type { DeviceEnrollment } from "../device-enrollment.js";
|
|
|
8
8
|
import type { DeviceStore } from "../device-store.js";
|
|
9
9
|
import type { ExecutionPlacementSeat } from "../execution-placement.js";
|
|
10
10
|
import type { DeviceWsHub } from "../device-ws-hub.js";
|
|
11
|
+
import { type RemoteContainerEnvDeps } from "../plugins/remote-env-e2b.js";
|
|
12
|
+
import { type WorkspaceFillOf } from "../plugins/workspace-fill.js";
|
|
11
13
|
import { k8sExecutionEnvFactory, type K8sEnvConfig, type K8sEnvDeps, type SandboxSecretSeat } from "../plugins/remote-env-k8s.js";
|
|
12
|
-
import { type
|
|
14
|
+
import { type SandboxGitPlaneSeat, type SandboxGitRunRows } from "../sandbox-git-plane.js";
|
|
13
15
|
import { type SandboxPodReaper } from "../plugins/k8s-pod-reaper.js";
|
|
14
16
|
import { type SpaceCommitRows } from "../workspace-space-commit.js";
|
|
17
|
+
import { type LocalDockerEnvDeps } from "../plugins/remote-env-local-docker.js";
|
|
15
18
|
import * as facts from "../capability-facts.js";
|
|
16
19
|
import { type TaskAttachmentStore } from "../plugins/task-attachment-store.js";
|
|
17
20
|
import type { TaskInheritEnv } from "../request-value-closure.js";
|
|
@@ -77,10 +80,19 @@ export declare function createSessionScopedRegistries(maxEntries?: number): Sess
|
|
|
77
80
|
* · 运维行座(`logger`)随部署级配置走。
|
|
78
81
|
* `deps` = 适配器自己的测试缝(假集群 / 假对象存储),生产装配不传。返回的是工厂闭包 ⇒ `create*`。
|
|
79
82
|
*/
|
|
83
|
+
/**
|
|
84
|
+
* 一条 run 是不是它工作区的属主:它的放置根就是它自己的会话(core `ExecutionEnvFactoryContext.placementRootSessionId`)。委派子代 / 后台代理与父 run 并发
|
|
85
|
+
* (一只工作区两个写者)、本服务为自己起的 run(放置根 = `INTERNAL_RUN_PLACEMENT_ROOT`)都不是。两个读者同一判:k8s 工作区空间(子代依律关)与
|
|
86
|
+
* 恢复点的播种(只有属主播种)。
|
|
87
|
+
*/
|
|
88
|
+
export declare function ownsItsWorkspace(ctx: {
|
|
89
|
+
readonly sessionId: string;
|
|
90
|
+
readonly placementRootSessionId: string;
|
|
91
|
+
}): boolean;
|
|
80
92
|
export declare function createK8sRunEnvFactory(k8sCfg: K8sEnvConfig, seats: {
|
|
81
93
|
imageOf(sessionId: string): string | undefined;
|
|
82
94
|
/** The member git-credential broker seat for the pod's run (`runId` = the one reading of the run that owns the pod, the same value its
|
|
83
|
-
* `sema.io/run` label carries; `sandbox-git-plane.ts` `
|
|
95
|
+
* `sema.io/run` label carries; `sandbox-git-plane.ts` `createSandboxBrokerSeatOf` over the plane seat's reading at that pod and the run row's identity);
|
|
84
96
|
* absent seat / `undefined` answer ⇒ the pod carries no broker. */
|
|
85
97
|
brokerSeatOf?(runId: string | undefined): Promise<K8sEnvConfig["sandboxBroker"]>;
|
|
86
98
|
/** The session store's by-id head read (`SessionStore.headOf`, picked once by `headReadOf`); the occupant is its live-occupant projection
|
|
@@ -90,11 +102,13 @@ export declare function createK8sRunEnvFactory(k8sCfg: K8sEnvConfig, seats: {
|
|
|
90
102
|
/** The run store's commit-fence rows (`workspace_space_commit`); answers `undefined` only before stage 7 binds the run store
|
|
91
103
|
* or without a store backend — the latter `assertWorkspaceSpaceReadable` refuses together with `space`. */
|
|
92
104
|
spaceCommits(): SpaceCommitRows | undefined;
|
|
105
|
+
/** The restore point's fill seat of the run (`workspace-fill.ts`; `createExecutionEnv` mints the one reading). Absent / `undefined` ⇒ the pod as it comes. */
|
|
106
|
+
workspaceFillOf?: WorkspaceFillOf;
|
|
93
107
|
}, deps?: K8sEnvDeps): ReturnType<typeof k8sExecutionEnvFactory>;
|
|
94
108
|
/**
|
|
95
109
|
* k8s 车道沙箱秘密座的**起服前提**(装配后的真门,第 5 段 await)。法只有一条:**秘密座非空(`K8S_SANDBOX_ENV` 点到了本进程环境里有的键)⇒
|
|
96
110
|
* 问一次 SelfSubjectAccessReview(env 座那一行动词 {@link SANDBOX_SECRET_SEAT_VERBS}`.env`,沙箱命名空间)** —— 只问这一座自己发的调用,
|
|
97
|
-
* 不问租约座的 `patch`(
|
|
111
|
+
* 不问租约座的 `patch`(那一座由凭据平面座在它的前提都成立时另问一次,见 `sandbox-git-plane.ts` 的 `createSandboxGitPlaneSeat` 的 `settle`):
|
|
98
112
|
* · 答了「不许」(任一动词)⇒ 拒启,一行拒句点名缺的动词、命名空间、Role 规则原文与出路(`[sandbox-secret-rbac]`)—— 不等第一个 run 才失败;
|
|
99
113
|
* · 问不到(请求失败 / 审查本身被拒 / 答复没有 `status.allowed`)⇒ 照常起服:F 类兜底口 `server.sandbox-secret.seat-unverified` 计数 + 一行
|
|
100
114
|
* `sandbox_secret_seat_unverified`。放行的最坏后果:RBAC 真缺时第一个要建 Secret 的 run 连接即拒(`auth_failed`,pod 被删)—— 秘密值仍然
|
|
@@ -141,6 +155,12 @@ export interface ExecutionEnvCtx {
|
|
|
141
155
|
/** run 店的按 id 读(成员凭据代理座读 run 行上受理时记下的身份元组 `RunRecord.identity`)。取值闭包:run 店第 7 段才绑(`late-binds.ts`),
|
|
142
156
|
* 平面开着时每个 run 的 pod 建起前求值一次。不传 / 答 `undefined`(没有存储后端)⇒ 读不到身份 ⇒ 不挂代理。 */
|
|
143
157
|
runRows?: () => SandboxGitRunRows | undefined;
|
|
158
|
+
/** 隔离车道三只适配器自己的测试缝(假 e2b SDK / 假集群 / 假 docker CLI),原样交给各自的工厂 —— 与 `K8sEnvDeps` 同一条律:生产装配不传。 */
|
|
159
|
+
laneDeps?: {
|
|
160
|
+
readonly e2b?: RemoteContainerEnvDeps;
|
|
161
|
+
readonly k8s?: K8sEnvDeps;
|
|
162
|
+
readonly localDocker?: LocalDockerEnvDeps;
|
|
163
|
+
};
|
|
144
164
|
}
|
|
145
165
|
export declare function createExecutionEnv(ctx: ExecutionEnvCtx): {
|
|
146
166
|
perTaskImage: PerTaskImageRegistry;
|
|
@@ -158,6 +178,6 @@ export declare function createExecutionEnv(ctx: ExecutionEnvCtx): {
|
|
|
158
178
|
spaceReclaimer: SpaceReclaimer | undefined;
|
|
159
179
|
sandboxSecretSeatGate: (() => Promise<void>) | undefined;
|
|
160
180
|
sandboxPodReaper: SandboxPodReaper | undefined;
|
|
161
|
-
|
|
181
|
+
sandboxGitPlane: SandboxGitPlaneSeat;
|
|
162
182
|
};
|
|
163
183
|
//# sourceMappingURL=execution-env.d.ts.map
|
|
@@ -11,10 +11,11 @@ import { PerTaskImageRegistry } from "../per-task-image.js";
|
|
|
11
11
|
import { adbExecutionEnvFactory } from "../plugins/remote-env-adb.js";
|
|
12
12
|
import { deviceExecutionEnvFactory } from "../plugins/remote-env-device.js";
|
|
13
13
|
import { e2bExecutionEnvFactory } from "../plugins/remote-env-e2b.js";
|
|
14
|
+
import { createWorkspaceFill } from "../plugins/workspace-fill.js";
|
|
14
15
|
import { hostExecutionEnvFactory, RemoteHostExecutionEnv } from "../plugins/remote-env-host.js";
|
|
15
16
|
import { boundedStoreCall, checkSandboxEgressPolicy, createSandboxPodApi, createSpaceReclaimer, k8sExecutionEnvFactory, readSandboxSecretSeat, rpcTimeoutMsOf } from "../plugins/remote-env-k8s.js";
|
|
16
17
|
import { podSpecPatchBrokerRefusal, SANDBOX_SECRET_SEAT_VERBS } from "../plugins/k8s-exec-protocol.js";
|
|
17
|
-
import {
|
|
18
|
+
import { createSandboxBrokerSeatOf, createSandboxGitPlaneSeat, sandboxGitPlanePremisesOf } from "../sandbox-git-plane.js";
|
|
18
19
|
import { createSandboxPodReaper } from "../plugins/k8s-pod-reaper.js";
|
|
19
20
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
20
21
|
import { createRunWorkspaceSnapshotSeat } from "../fleet/workspace-snapshot-residual.js";
|
|
@@ -38,6 +39,7 @@ import { sandboxPathEnvSlots, withSandboxPathEnvSlot } from "./deferred-sandbox-
|
|
|
38
39
|
import { createLaneHomeAbsenceReporter } from "../lane-home-probe.js";
|
|
39
40
|
import { REMOTE_EXEC_PROVIDER_WORDS, buildLaneHomeBootNote, buildLaneHomeClaim, capabilitiesFor, executionLaneOf, laneBindsReads, laneIsolated, laneSandboxReadFloorState } from "../execution-lane-caps.js";
|
|
40
41
|
import { warnReadDenyFloorUnkept } from "./execution-lane.js";
|
|
42
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
41
43
|
function boundedSessionSetter(map, maxEntries) {
|
|
42
44
|
return (sid, value) => {
|
|
43
45
|
map.delete(sid);
|
|
@@ -105,15 +107,19 @@ export function createSessionScopedRegistries(maxEntries = MAX_CWD_SESSIONS) {
|
|
|
105
107
|
dropSession,
|
|
106
108
|
};
|
|
107
109
|
}
|
|
110
|
+
export function ownsItsWorkspace(ctx) {
|
|
111
|
+
return ctx.placementRootSessionId === ctx.sessionId;
|
|
112
|
+
}
|
|
108
113
|
export function createK8sRunEnvFactory(k8sCfg, seats, deps) {
|
|
109
114
|
const cacheMisses = createCacheMissMemory();
|
|
110
115
|
return async (ctx) => {
|
|
111
116
|
const onWorkspaceSnapshot = createRunWorkspaceSnapshotSeat(ctx.sessionId);
|
|
112
|
-
const child = ctx
|
|
117
|
+
const child = !ownsItsWorkspace(ctx);
|
|
113
118
|
const s3Snapshot = child && k8sCfg.s3Snapshot !== undefined ? spaceOff(k8sCfg.s3Snapshot) : k8sCfg.s3Snapshot;
|
|
114
119
|
const spaceOccupant = child ? undefined : await occupantOf(seats, ctx.sessionId, ctx.taskId, rpcTimeoutMsOf(k8sCfg));
|
|
115
120
|
const runId = !child && ctx.taskId !== undefined ? ctx.taskId : undefined;
|
|
116
121
|
const sandboxBroker = await seats.brokerSeatOf?.(runId);
|
|
122
|
+
const workspaceFill = seats.workspaceFillOf?.(ctx);
|
|
117
123
|
const { cache, ...deploymentCfg } = k8sCfg;
|
|
118
124
|
return k8sExecutionEnvFactory({
|
|
119
125
|
...deploymentCfg,
|
|
@@ -123,6 +129,7 @@ export function createK8sRunEnvFactory(k8sCfg, seats, deps) {
|
|
|
123
129
|
...(spaceOccupant !== undefined ? { spaceOccupant } : {}),
|
|
124
130
|
...(runId !== undefined ? { runId } : {}),
|
|
125
131
|
...(sandboxBroker !== undefined ? { sandboxBroker } : {}),
|
|
132
|
+
...(workspaceFill !== undefined ? { workspaceFill } : {}),
|
|
126
133
|
onWorkspaceSnapshot,
|
|
127
134
|
}, deps)(ctx);
|
|
128
135
|
};
|
|
@@ -171,7 +178,7 @@ export async function ensureSandboxSecretSeat(k8sCfg, logger, deps, read = () =>
|
|
|
171
178
|
recordFailOpen("server.sandbox-secret.seat-unverified", `namespace=${namespace} ${seat.detail}`);
|
|
172
179
|
logger.warn("sandbox_secret_seat_unverified", {
|
|
173
180
|
namespace,
|
|
174
|
-
detail: seat.detail,
|
|
181
|
+
detail: seatText("operator-log-text", seat.detail),
|
|
175
182
|
effect: `the boot could not confirm the sandbox Secret RBAC (secrets ${SANDBOX_SECRET_SEAT_VERBS.env.join(" / ")}) — the service starts; if the Role lacks them, the first run that forwards K8S_SANDBOX_ENV is refused at connect (auth_failed) and its pod deleted — the values never go into the pod spec`,
|
|
176
183
|
});
|
|
177
184
|
return;
|
|
@@ -239,9 +246,9 @@ export function createExecutionEnv(ctx) {
|
|
|
239
246
|
let spaceReclaimer;
|
|
240
247
|
let sandboxSecretSeatGate;
|
|
241
248
|
let sandboxPodReaper;
|
|
242
|
-
|
|
243
|
-
let readSandboxGitPlane = async () => (planeCell.current = judgeSandboxGitPlane(sandboxGitPlanePremisesOf(config, {})));
|
|
249
|
+
let sandboxGitPlane = createSandboxGitPlaneSeat((r) => sandboxGitPlanePremisesOf(config, r), {});
|
|
244
250
|
let worktreeReap;
|
|
251
|
+
const workspaceFillOf = taskAttachmentStore === undefined ? undefined : (fctx) => createWorkspaceFill({ store: taskAttachmentStore, sessionId: fctx.sessionId, seeds: ownsItsWorkspace(fctx), logger });
|
|
245
252
|
if (config.remoteExec?.provider === "e2b") {
|
|
246
253
|
executionEnvFactory = e2bExecutionEnvFactory({
|
|
247
254
|
apiKey: config.remoteExec.apiKey,
|
|
@@ -253,9 +260,10 @@ export function createExecutionEnv(ctx) {
|
|
|
253
260
|
...(config.remoteExec.mountPath ? { mountPath: config.remoteExec.mountPath } : {}),
|
|
254
261
|
...((env) => (env !== undefined ? { sandboxEnv: env } : {}))(sandboxLaneEnvMerged(buildSandboxLaneEnv(config, config.remoteExec.sandboxEnv))),
|
|
255
262
|
sandboxReadFloor: config.sandboxReadFloor,
|
|
263
|
+
...(workspaceFillOf !== undefined ? { workspaceFillOf } : {}),
|
|
256
264
|
logger,
|
|
257
265
|
metrics,
|
|
258
|
-
});
|
|
266
|
+
}, ctx.laneDeps?.e2b);
|
|
259
267
|
}
|
|
260
268
|
else if (config.remoteExec?.provider === "k8s") {
|
|
261
269
|
const k8sCfg = {
|
|
@@ -281,30 +289,24 @@ export function createExecutionEnv(ctx) {
|
|
|
281
289
|
...((lane) => ({ ...(lane.env !== undefined ? { podEnv: lane.env } : {}), ...(lane.secretEnv !== undefined ? { podSecretEnv: lane.secretEnv } : {}) }))(buildSandboxLaneEnv(config, config.remoteExec.sandboxEnv)),
|
|
282
290
|
sandboxReadFloor: config.sandboxReadFloor,
|
|
283
291
|
};
|
|
284
|
-
|
|
292
|
+
sandboxGitPlane = createSandboxGitPlaneSeat((r) => sandboxGitPlanePremisesOf(config, r), {
|
|
293
|
+
patchRefusal: podSpecPatchBrokerRefusal(k8sCfg.podSpecPatch),
|
|
294
|
+
askSecretSeat: () => readSandboxSecretSeat(k8sCfg, "lease"),
|
|
295
|
+
});
|
|
285
296
|
executionEnvFactory = createK8sRunEnvFactory(k8sCfg, {
|
|
286
297
|
imageOf: (sid) => perTaskImage.get(sid),
|
|
287
298
|
headOf: ctx.headOf,
|
|
288
299
|
spaceCommits: ctx.spaceCommits ?? (() => undefined),
|
|
289
|
-
brokerSeatOf:
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
return undefined;
|
|
293
|
-
return sandboxBrokerSeatOf(plane, brokerImage, await runIdentitySourceOf(runId, ctx.runRows?.(), logger));
|
|
294
|
-
},
|
|
295
|
-
});
|
|
300
|
+
brokerSeatOf: createSandboxBrokerSeatOf(sandboxGitPlane.now, config.remoteExec.brokerImage, ctx.runRows, logger),
|
|
301
|
+
...(workspaceFillOf !== undefined ? { workspaceFillOf } : {}),
|
|
302
|
+
}, ctx.laneDeps?.k8s);
|
|
296
303
|
if (k8sCfg.cache !== undefined || k8sCfg.s3Snapshot !== undefined)
|
|
297
304
|
spaceReclaimer = createSpaceReclaimer(k8sCfg);
|
|
298
305
|
sandboxSecretSeatGate = () => ensureSandboxSecretSeat(k8sCfg, logger, undefined, () => readSandboxSecretSeat(k8sCfg, "env"));
|
|
299
|
-
readSandboxGitPlane = async () => {
|
|
300
|
-
const premises = sandboxGitPlanePremisesOf(config, { ...((r) => (r !== undefined ? { patchRefusal: r } : {}))(podSpecPatchBrokerRefusal(k8sCfg.podSpecPatch)) });
|
|
301
|
-
const secretSeat = sandboxGitPlaneAsksSecretSeat(premises) ? await readSandboxSecretSeat(k8sCfg, "lease") : undefined;
|
|
302
|
-
return (planeCell.current = judgeSandboxGitPlane({ ...premises, secretSeat }));
|
|
303
|
-
};
|
|
304
306
|
sandboxPodReaper = createSandboxPodReaper({ api: createSandboxPodApi(k8sCfg), logger, metrics });
|
|
305
307
|
void checkSandboxEgressPolicy(k8sCfg)
|
|
306
308
|
.then((gaps) => sayEgressPolicyReading(gaps, logger, k8sCfg.namespace))
|
|
307
|
-
.catch((e) => logger.error("sandbox_egress_policy_check_crashed", { error: e instanceof Error ? e.message : String(e), effect: "the sandbox egress self-check did not complete this boot — the lane runs; the egress policy was not read" }));
|
|
309
|
+
.catch((e) => logger.error("sandbox_egress_policy_check_crashed", { error: seatText("operator-log-text", e instanceof Error ? e.message : String(e)), effect: "the sandbox egress self-check did not complete this boot — the lane runs; the egress policy was not read" }));
|
|
308
310
|
}
|
|
309
311
|
else if (config.remoteExec?.provider === "ssh") {
|
|
310
312
|
executionEnvFactory = sshExecutionEnvFactory({
|
|
@@ -397,7 +399,8 @@ export function createExecutionEnv(ctx) {
|
|
|
397
399
|
...(config.remoteExec.commandTimeoutMs != null ? { commandTimeoutMs: config.remoteExec.commandTimeoutMs } : {}),
|
|
398
400
|
...(config.remoteExec.env ? { env: config.remoteExec.env } : {}),
|
|
399
401
|
sandboxReadFloor: config.sandboxReadFloor,
|
|
400
|
-
|
|
402
|
+
...(workspaceFillOf !== undefined ? { workspaceFillOf } : {}),
|
|
403
|
+
}, ctx.laneDeps?.localDocker);
|
|
401
404
|
}
|
|
402
405
|
if (executionEnvFactory && DEPLOYMENT_SHAPE_PREDICATES.remoteScratchpad.holds(config)) {
|
|
403
406
|
executionEnvFactory = withRemoteScratchpad(executionEnvFactory, logger);
|
|
@@ -451,7 +454,7 @@ export function createExecutionEnv(ctx) {
|
|
|
451
454
|
executionEnvFactory = registry.wrapFactory(executionEnvFactory);
|
|
452
455
|
return registry;
|
|
453
456
|
})();
|
|
454
|
-
if (taskAttachmentStore && executionEnvFactory) {
|
|
457
|
+
if (taskAttachmentStore && executionEnvFactory && !laneIsolated(executionLaneOf(config.remoteExec.provider))) {
|
|
455
458
|
const inner = executionEnvFactory;
|
|
456
459
|
const attStore = taskAttachmentStore;
|
|
457
460
|
executionEnvFactory = async (ctx) => {
|
|
@@ -507,7 +510,7 @@ export function createExecutionEnv(ctx) {
|
|
|
507
510
|
perTaskImage, sessionEnvSelection, perSessionCwd, setSessionCwd, setSessionShellEnv, setSessionInheritEnv,
|
|
508
511
|
fenceSessionOwner: sessionScoped.fenceSessionOwner,
|
|
509
512
|
dropSessionScoped: sessionScoped.dropSession,
|
|
510
|
-
executionEnvFactory, worktreeReap, sendUserFileTaskEnvs, lspManager, spaceReclaimer, sandboxSecretSeatGate, sandboxPodReaper,
|
|
513
|
+
executionEnvFactory, worktreeReap, sendUserFileTaskEnvs, lspManager, spaceReclaimer, sandboxSecretSeatGate, sandboxPodReaper, sandboxGitPlane,
|
|
511
514
|
};
|
|
512
515
|
}
|
|
513
516
|
//# sourceMappingURL=execution-env.js.map
|
|
@@ -4,6 +4,7 @@ import { crossInvariant } from "../config-invariants.js";
|
|
|
4
4
|
import { buildReadDenyFloorUnkeptNote, executionLaneOf, laneIsolated } from "../execution-lane-caps.js";
|
|
5
5
|
import { buildReadFacePostureNotice, settleDerivedReadFace } from "../read-face-posture.js";
|
|
6
6
|
import { settleHostShellAtBoot } from "../plugins/host-platform.js";
|
|
7
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
7
8
|
export const FILE_SOURCED_LANES = ["host", "local-docker"];
|
|
8
9
|
export async function composeExecutionLane(config, ctx) {
|
|
9
10
|
if (ctx.configSource === "local")
|
|
@@ -55,7 +56,7 @@ async function applyRemoteExecFile(config, ctx) {
|
|
|
55
56
|
fileRx = await loadRemoteExec(localRoot);
|
|
56
57
|
}
|
|
57
58
|
catch (err) {
|
|
58
|
-
logger.error("remote_exec_file_invalid", { root: localRoot, err: String(err) });
|
|
59
|
+
logger.error("remote_exec_file_invalid", { root: localRoot, err: seatText("operator-log-text", String(err)) });
|
|
59
60
|
throw new Error(`config.d/remote-exec.json under ${localRoot} is invalid: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
60
61
|
}
|
|
61
62
|
if (!fileRx)
|
|
@@ -2,6 +2,7 @@ import { defaultTaskRegistry } from "@sema-agent/core";
|
|
|
2
2
|
import { reportHardKillReceipts } from "../background-session-reap.js";
|
|
3
3
|
import { liveHostForegroundChildCount, reapHostForegroundChildren } from "../plugins/host-platform.js";
|
|
4
4
|
import { liveEphemeralHostWorkspaceCount, reapEphemeralHostWorkspaces } from "../plugins/host-workspace-registry.js";
|
|
5
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
5
6
|
const PROCESS_EXIT_INCLUDES_RETAINED = false;
|
|
6
7
|
export function installProcessExitBoundary({ logger }) {
|
|
7
8
|
const reapOwnChildProcesses = () => {
|
|
@@ -13,7 +14,7 @@ export function installProcessExitBoundary({ logger }) {
|
|
|
13
14
|
logger.info("shutdown_background_reaped", { reaped });
|
|
14
15
|
}
|
|
15
16
|
catch (err) {
|
|
16
|
-
logger.warn("shutdown_background_reap_failed", { err: String(err) });
|
|
17
|
+
logger.warn("shutdown_background_reap_failed", { err: seatText("operator-log-text", String(err)) });
|
|
17
18
|
}
|
|
18
19
|
try {
|
|
19
20
|
const fg = reapHostForegroundChildren();
|
|
@@ -23,7 +24,7 @@ export function installProcessExitBoundary({ logger }) {
|
|
|
23
24
|
logger.warn("shutdown_foreground_reap_incomplete", { groups: fg.failed });
|
|
24
25
|
}
|
|
25
26
|
catch (err) {
|
|
26
|
-
logger.warn("shutdown_foreground_reap_failed", { err: String(err) });
|
|
27
|
+
logger.warn("shutdown_foreground_reap_failed", { err: seatText("operator-log-text", String(err)) });
|
|
27
28
|
}
|
|
28
29
|
return backgroundSoftStopped;
|
|
29
30
|
};
|
|
@@ -33,7 +34,7 @@ export function installProcessExitBoundary({ logger }) {
|
|
|
33
34
|
reportHardKillReceipts(logger, receipts, "process_exit");
|
|
34
35
|
}
|
|
35
36
|
catch (err) {
|
|
36
|
-
logger.warn("shutdown_background_hard_kill_failed", { err: String(err) });
|
|
37
|
+
logger.warn("shutdown_background_hard_kill_failed", { err: seatText("operator-log-text", String(err)) });
|
|
37
38
|
}
|
|
38
39
|
};
|
|
39
40
|
const reapOwnHostWorkspaces = () => {
|
|
@@ -45,7 +46,7 @@ export function installProcessExitBoundary({ logger }) {
|
|
|
45
46
|
logger.warn("shutdown_host_workspace_reap_incomplete", { dirs: failed.map((f) => f.dir) });
|
|
46
47
|
}
|
|
47
48
|
catch (err) {
|
|
48
|
-
logger.warn("shutdown_host_workspace_reap_failed", { err: String(err) });
|
|
49
|
+
logger.warn("shutdown_host_workspace_reap_failed", { err: seatText("operator-log-text", String(err)) });
|
|
49
50
|
}
|
|
50
51
|
};
|
|
51
52
|
const onProcessExit = () => {
|