@sema-agent/server 7.52.1 → 7.54.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/USAGE.md +7 -1
- package/dist/adoption/plan.d.ts +3 -3
- package/dist/adoption/quiesce.d.ts +1 -1
- package/dist/adoption/sql.d.ts +2 -2
- package/dist/adoption/wire.d.ts +1 -1
- package/dist/approval-ask-machine.d.ts +2 -2
- package/dist/approval-card.d.ts +18 -18
- package/dist/approval-deny-reasons.d.ts +1 -1
- package/dist/approval-hmac.d.ts +2 -2
- package/dist/approval-reconciler.d.ts +14 -14
- package/dist/approval.d.ts +2 -2
- package/dist/audit.d.ts +4 -4
- package/dist/auth-keys.d.ts +6 -6
- package/dist/bench/l8/artifact.d.ts +6 -1
- package/dist/bench/l8/artifact.js +2 -27
- package/dist/bench/l8/escape.d.ts +3 -3
- package/dist/bench/l8/index.d.ts +1 -1
- package/dist/bench/s1/arms.d.ts +3 -3
- package/dist/bench/s1/oracle.d.ts +2 -2
- package/dist/bench/s1/reviewer.d.ts +1 -1
- package/dist/bench/s1/row.d.ts +5 -5
- package/dist/bench/s1/runner-ctx.d.ts +3 -3
- package/dist/boot/config-center.d.ts +14 -7
- package/dist/boot/config-center.js +4 -2
- package/dist/boot/coordinators.d.ts +4 -4
- package/dist/boot/crash-last.d.ts +1 -1
- package/dist/boot/device-lane.d.ts +3 -3
- package/dist/boot/engine-lease.d.ts +4 -4
- package/dist/boot/governance-seams.d.ts +5 -5
- package/dist/boot/leader.d.ts +5 -5
- package/dist/boot/leader.js +2 -0
- package/dist/boot/limit-sync.d.ts +1 -1
- package/dist/boot/memory-boundary.d.ts +5 -5
- package/dist/boot/memory-consolidation.d.ts +8 -2
- package/dist/boot/memory-consolidation.js +1 -0
- package/dist/boot/org-memory.d.ts +5 -5
- package/dist/boot/parked-revive-gate.d.ts +6 -6
- package/dist/boot/permission-rules-audit.d.ts +2 -2
- package/dist/boot/reapers.d.ts +8 -8
- package/dist/boot/resolve-spec.d.ts +4 -4
- package/dist/boot/resolve-spec.js +1 -3
- package/dist/boot/retention-lane.d.ts +1 -1
- package/dist/boot/runner-deps.d.ts +53 -27
- package/dist/boot/runner-deps.js +16 -9
- package/dist/boot/runtime-caps.d.ts +4 -4
- package/dist/boot/session-faces.d.ts +1 -1
- package/dist/boot/shutdown.d.ts +10 -10
- package/dist/boot/shutdown.js +1 -1
- package/dist/boot/side-query-lane.d.ts +14 -14
- package/dist/boot/stores.js +5 -0
- package/dist/boot/task-list-lane.d.ts +3 -3
- package/dist/boot/webfetch-summarize-lane.d.ts +9 -9
- package/dist/boot/workflow-orchestration.d.ts +1 -1
- package/dist/bounded-session-map.d.ts +1 -1
- package/dist/brain.d.ts +3 -3
- package/dist/budget.d.ts +3 -3
- package/dist/canonical-json.d.ts +53 -0
- package/dist/canonical-json.js +48 -0
- package/dist/capabilities/center-prompts.d.ts +13 -13
- package/dist/capabilities/collab-workflows.d.ts +1 -1
- package/dist/capabilities/hands-lane.d.ts +4 -4
- package/dist/capabilities/memory-notice.d.ts +4 -4
- package/dist/capabilities/prompt.d.ts +2 -2
- package/dist/capabilities/sandbox-file-send.d.ts +2 -2
- package/dist/capabilities/scenarios.d.ts +16 -16
- package/dist/capabilities/skills.d.ts +1 -1
- package/dist/capabilities/team.d.ts +13 -12
- package/dist/capabilities/tool-defer.d.ts +6 -6
- package/dist/config-catalog.d.ts +139 -0
- package/dist/config-catalog.js +556 -0
- package/dist/config-center/apply-effective.d.ts +42 -30
- package/dist/config-center/apply-effective.js +69 -62
- package/dist/config-center/apply-ledger.d.ts +6 -6
- package/dist/config-center/effective-keys.d.ts +30 -0
- package/dist/config-center/effective-keys.js +49 -0
- package/dist/config-center/facade.d.ts +6 -5
- package/dist/config-center/facade.js +1 -1
- package/dist/config-center/hot-keys-registry.d.ts +2 -2
- package/dist/config-center/http-client.d.ts +5 -5
- package/dist/config-center/mcp-revocation.d.ts +6 -4
- package/dist/config-center/mcp-revocation.js +2 -12
- package/dist/config-center/restart-signal.d.ts +11 -1
- package/dist/config-center/restart-signal.js +4 -10
- package/dist/config-center/skills-mcp.d.ts +2 -2
- package/dist/config-center/stage-limits.d.ts +3 -3
- package/dist/config-center/types.d.ts +42 -59
- package/dist/config-invariants.d.ts +1 -1
- package/dist/config-lkg.js +7 -1
- package/dist/config-provider.d.ts +2 -2
- package/dist/config-provider.js +1 -1
- package/dist/config-types.d.ts +140 -132
- package/dist/config.d.ts +22 -22
- package/dist/config.js +2 -1
- package/dist/degenerate-instrument.d.ts +1 -1
- package/dist/deployment-governance.d.ts +13 -13
- package/dist/device-enrollment.d.ts +5 -3
- package/dist/device-store.d.ts +17 -3
- package/dist/device-store.js +2 -0
- package/dist/device-ws-hub.d.ts +10 -5
- package/dist/device-ws-hub.js +25 -5
- package/dist/device-ws-protocol.d.ts +3 -3
- package/dist/digest-form.d.ts +1 -1
- package/dist/elicitation.d.ts +1 -1
- package/dist/env-facts.d.ts +7 -7
- package/dist/execution-lane-caps.d.ts +5 -5
- package/dist/fleet/fleet-bus.d.ts +53 -53
- package/dist/fleet/fleet-reconciler.d.ts +2 -2
- package/dist/fleet/fleet-terminal-window.d.ts +1 -1
- package/dist/fleet/subagent-tail-bus.d.ts +3 -3
- package/dist/fleet-client.d.ts +3 -3
- package/dist/fleet-lease.d.ts +1 -1
- package/dist/hooks/branch-transcript.d.ts +2 -2
- package/dist/hooks/cc-agent-hook-prompt.d.ts +2 -2
- package/dist/hooks/cc-stop-prompt.d.ts +2 -2
- package/dist/hooks/hook-llm.d.ts +1 -1
- package/dist/hooks/hook-runner.d.ts +5 -5
- package/dist/http/active-run-conflict.d.ts +31 -33
- package/dist/http/active-run-conflict.js +4 -2
- package/dist/http/route-ctx.d.ts +22 -22
- package/dist/http/routes/a2a-serve.d.ts +2 -2
- package/dist/http/routes/admin-config-refresh.d.ts +1 -1
- package/dist/http/routes/admin-drain.d.ts +4 -4
- package/dist/http/routes/admin-memory-optout.d.ts +5 -5
- package/dist/http/routes/adoption.d.ts +1 -1
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/approvals-assistant.d.ts +6 -6
- package/dist/http/routes/approvals-assistant.js +4 -1
- package/dist/http/routes/capabilities.d.ts +1 -1
- package/dist/http/routes/capabilities.js +1 -0
- package/dist/http/routes/config-catalog.d.ts +28 -0
- package/dist/http/routes/config-catalog.js +42 -0
- package/dist/http/routes/diagnostics.d.ts +2 -2
- package/dist/http/routes/fleet.d.ts +1 -1
- package/dist/http/routes/images.d.ts +1 -1
- package/dist/http/routes/leader.d.ts +1 -1
- package/dist/http/routes/memory-bundle.d.ts +4 -4
- package/dist/http/routes/memory-compliance.d.ts +7 -7
- package/dist/http/routes/memory-consolidation.d.ts +1 -1
- package/dist/http/routes/memory-origin.d.ts +9 -9
- package/dist/http/routes/memory-policy.d.ts +3 -3
- package/dist/http/routes/notify-wake.d.ts +1 -1
- package/dist/http/routes/observability.d.ts +1 -1
- package/dist/http/routes/retention-ops.d.ts +1 -1
- package/dist/http/routes/rules.d.ts +3 -3
- package/dist/http/routes/run-memory-capture.d.ts +1 -1
- package/dist/http/routes/runs.d.ts +3 -3
- package/dist/http/routes/runs.js +12 -17
- package/dist/http/routes/session-sync.d.ts +2 -2
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/sessions.d.ts +9 -1
- package/dist/http/routes/sessions.js +60 -0
- package/dist/http/routes/shared-memory.d.ts +1 -1
- package/dist/http/routes/side-query.d.ts +1 -1
- package/dist/http/routes/tasks.d.ts +1 -1
- package/dist/http/routes/trace-usage.d.ts +1 -1
- package/dist/http/routes/workflows.d.ts +1 -1
- package/dist/http/run-meta.d.ts +1 -1
- package/dist/http/send.d.ts +6 -6
- package/dist/http/server.d.ts +84 -67
- package/dist/http/server.js +39 -10
- package/dist/http/sse-lifecycle.d.ts +1 -1
- package/dist/http/sse-log.d.ts +6 -6
- package/dist/http/verify-rounds.d.ts +3 -3
- package/dist/http/wire-gate.d.ts +2 -2
- package/dist/http/wire-types.d.ts +57 -38
- package/dist/key-resolver.d.ts +1 -1
- package/dist/leader/diffout.d.ts +2 -2
- package/dist/leader/diffup.d.ts +1 -1
- package/dist/leader/endpoint.d.ts +1 -1
- package/dist/leader/fanout.d.ts +6 -6
- package/dist/leader/grader-env-factory.d.ts +1 -1
- package/dist/leader/leader.d.ts +12 -12
- package/dist/leader/merge.d.ts +3 -3
- package/dist/leader/planner.d.ts +5 -5
- package/dist/leader/repair-oracle.d.ts +1 -1
- package/dist/leader/wire.d.ts +21 -9
- package/dist/leader/wire.js +6 -5
- package/dist/lsp/manager.d.ts +2 -2
- package/dist/lsp/types.d.ts +1 -1
- package/dist/lsp/ws-transport.d.ts +2 -2
- package/dist/main.js +12 -2
- package/dist/mcp-content-origin.d.ts +1 -1
- package/dist/memory-bundle-engine.d.ts +5 -3
- package/dist/memory-bundle-engine.js +2 -2
- package/dist/memory-operator-faces.d.ts +41 -11
- package/dist/memory-operator-faces.js +12 -0
- package/dist/memory-origin-fence.d.ts +1 -1
- package/dist/memory-origin-fence.js +2 -13
- package/dist/memory-posture.d.ts +6 -6
- package/dist/memory-scope.d.ts +7 -7
- package/dist/model-select.d.ts +5 -5
- package/dist/observability/cost-quota.d.ts +6 -6
- package/dist/observability/cost-taxonomy.d.ts +2 -2
- package/dist/observability/fail-open.d.ts +17 -5
- package/dist/observability/fail-open.js +16 -4
- package/dist/observability/metrics.d.ts +1 -1
- package/dist/observability/prompt-manifest.d.ts +8 -8
- package/dist/observability/rate-limit.d.ts +2 -2
- package/dist/observability/secret-env-scrub.d.ts +1 -1
- package/dist/observability/tool-trace.d.ts +1 -1
- package/dist/orchestration/hardened-vm-runner.d.ts +6 -6
- package/dist/orchestration/hardened-vm-worker-runner.d.ts +1 -1
- package/dist/orchestration/subagent-steer.d.ts +3 -3
- package/dist/orchestration/workflow-agent-steer.d.ts +1 -1
- package/dist/orchestration/workflow-completion-inbox.d.ts +6 -6
- package/dist/orchestration/workflow-notify-journal.d.ts +6 -6
- package/dist/parent-watch.d.ts +1 -1
- package/dist/parked-decide.d.ts +11 -11
- package/dist/plan-cache-probe.d.ts +1 -1
- package/dist/plugins/adoption-log-sql.d.ts +4 -4
- package/dist/plugins/approval-ask-store-memory.d.ts +1 -1
- package/dist/plugins/approval-ask-store-memory.js +12 -0
- package/dist/plugins/approval-ask-store-sql.d.ts +39 -17
- package/dist/plugins/approval-ask-store-sql.js +23 -6
- package/dist/plugins/approval-payload-fingerprint.d.ts +23 -0
- package/dist/plugins/approval-payload-fingerprint.js +23 -0
- package/dist/plugins/background-agent-store-sql.d.ts +8 -8
- package/dist/plugins/background-shell-support.d.ts +12 -12
- package/dist/plugins/blob-backend.d.ts +3 -3
- package/dist/plugins/breaker-state-sql.d.ts +3 -3
- package/dist/plugins/caching-session-store.d.ts +6 -6
- package/dist/plugins/checkpoint-store-sql.d.ts +162 -66
- package/dist/plugins/checkpoint-store-sql.js +76 -33
- package/dist/plugins/device-store-sql.d.ts +4 -3
- package/dist/plugins/e2b-orphan-reclaim.d.ts +3 -3
- package/dist/plugins/file-history-store-sql.d.ts +9 -8
- package/dist/plugins/file-run-store.d.ts +27 -27
- package/dist/plugins/fork-routing-session-store.d.ts +9 -9
- package/dist/plugins/image-bake-store-sql.d.ts +1 -1
- package/dist/plugins/image-index-sql.d.ts +2 -2
- package/dist/plugins/k8s-bg-scripts.d.ts +1 -1
- package/dist/plugins/k8s-exec-protocol.d.ts +1 -1
- package/dist/plugins/leader-run-store-sql.d.ts +1 -1
- package/dist/plugins/local-checkpoint-store.d.ts +26 -17
- package/dist/plugins/local-checkpoint-store.js +21 -11
- package/dist/plugins/local-session-store.d.ts +5 -5
- package/dist/plugins/mailbox-store-sql.d.ts +6 -6
- package/dist/plugins/memory-embedder-fingerprint.d.ts +2 -2
- package/dist/plugins/memory-engine-pg.d.ts +1 -1
- package/dist/plugins/memory-engine-tidb.d.ts +1 -1
- package/dist/plugins/memory-key-guards.d.ts +3 -3
- package/dist/plugins/memory-optout-grant-store-sql.d.ts +10 -10
- package/dist/plugins/memory-origin-law.d.ts +13 -13
- package/dist/plugins/memory-run-store.d.ts +12 -12
- package/dist/plugins/outcome-ledger-sql.d.ts +3 -3
- package/dist/plugins/permission-rule-store-file.d.ts +3 -3
- package/dist/plugins/permission-rule-store-sql.d.ts +38 -33
- package/dist/plugins/permission-rule-store-sql.js +7 -12
- package/dist/plugins/pg-cost-quota.d.ts +2 -2
- package/dist/plugins/pg-pool.d.ts +29 -2
- package/dist/plugins/pg-pool.js +50 -2
- package/dist/plugins/pg-query.d.ts +1 -1
- package/dist/plugins/pg-rate-limiter.d.ts +2 -2
- package/dist/plugins/pg-session-storage.d.ts +9 -9
- package/dist/plugins/remote-env-adb.d.ts +1 -1
- package/dist/plugins/remote-env-device.d.ts +6 -4
- package/dist/plugins/remote-env-device.js +4 -1
- package/dist/plugins/remote-env-e2b.d.ts +11 -11
- package/dist/plugins/remote-env-file-error.d.ts +2 -2
- package/dist/plugins/remote-env-host.d.ts +10 -10
- package/dist/plugins/remote-env-k8s.d.ts +7 -7
- package/dist/plugins/remote-env-local-docker.d.ts +1 -1
- package/dist/plugins/remote-env-ssh.d.ts +9 -9
- package/dist/plugins/remote-scratchpad.d.ts +1 -1
- package/dist/plugins/resume-anchor-store-sql.d.ts +1 -1
- package/dist/plugins/retention-lane-store-sql.d.ts +2 -2
- package/dist/plugins/retention-store-sql.d.ts +11 -11
- package/dist/plugins/roster-store-sql.d.ts +6 -8
- package/dist/plugins/run-store-sql.d.ts +12 -12
- package/dist/plugins/scheduler-support.d.ts +1 -1
- package/dist/plugins/send-user-file.d.ts +1 -1
- package/dist/plugins/session-capture-record-store-sql.d.ts +99 -0
- package/dist/plugins/session-capture-record-store-sql.js +110 -0
- package/dist/plugins/session-placement.d.ts +1 -1
- package/dist/plugins/session-policy-store-sql.d.ts +2 -2
- package/dist/plugins/session-store.d.ts +3 -3
- package/dist/plugins/shared-memory-store-sql.d.ts +5 -5
- package/dist/plugins/sql-driver.d.ts +7 -7
- package/dist/plugins/sql-errors.d.ts +2 -2
- package/dist/plugins/sql-escape.d.ts +1 -1
- package/dist/plugins/sql-row-helpers.d.ts +1 -1
- package/dist/plugins/store-backend.d.ts +32 -19
- package/dist/plugins/store-backend.js +5 -1
- package/dist/plugins/store-contracts.d.ts +9 -9
- package/dist/plugins/task-list-store-sql.d.ts +3 -3
- package/dist/plugins/tidb-cost-quota.d.ts +3 -3
- package/dist/plugins/tidb-pool.d.ts +13 -0
- package/dist/plugins/tidb-pool.js +9 -0
- package/dist/plugins/tidb-rate-limiter.d.ts +2 -2
- package/dist/plugins/tidb-session-storage.d.ts +2 -2
- package/dist/plugins/tidb-session-store.d.ts +11 -11
- package/dist/plugins/tool-result-store-sql.d.ts +8 -8
- package/dist/plugins/usage-window-store-sql.d.ts +3 -3
- package/dist/plugins/web-search.d.ts +7 -7
- package/dist/plugins/workflow-journal-store-sql.d.ts +6 -6
- package/dist/plugins/workflow-run-store-sql.d.ts +1 -1
- package/dist/plugins/write-behind-counter.d.ts +6 -6
- package/dist/principal-jwt.d.ts +2 -2
- package/dist/project-memory.d.ts +1 -1
- package/dist/prompts-domain-validate.d.ts +8 -8
- package/dist/question.d.ts +3 -3
- package/dist/resource-suspend.d.ts +4 -4
- package/dist/resource-window.d.ts +3 -3
- package/dist/router/route-orchestration.d.ts +1 -1
- package/dist/rules-consent.d.ts +48 -40
- package/dist/run-local.d.ts +5 -5
- package/dist/runs.d.ts +19 -19
- package/dist/runtime-caps-resolver.d.ts +6 -6
- package/dist/runtime-governance.d.ts +11 -7
- package/dist/runtime-governance.js +23 -1
- package/dist/security.d.ts +13 -13
- package/dist/session-leaf-bus.d.ts +1 -1
- package/dist/session-sync-content.d.ts +4 -4
- package/dist/session-sync-kernel.d.ts +2 -2
- package/dist/session-sync.d.ts +13 -13
- package/dist/session-titler.d.ts +1 -1
- package/dist/session-watch.d.ts +3 -3
- package/dist/shared-memory-scope-authorizer.d.ts +4 -4
- package/dist/sighup-idle.d.ts +1 -1
- package/dist/spec-fields.d.ts +20 -20
- package/dist/ssh-host-key.d.ts +5 -5
- package/dist/store-live-probe.d.ts +2 -2
- package/dist/task-cwd.d.ts +11 -11
- package/dist/task-mcp.d.ts +5 -5
- package/dist/task-settings.d.ts +35 -35
- package/dist/task-workflow.d.ts +3 -3
- package/dist/text-bidi.d.ts +1 -1
- package/dist/tool-approval.d.ts +186 -182
- package/dist/tool-approval.js +247 -120
- package/dist/trace/core-keyset-guard.d.ts +19 -5
- package/dist/trace/engine-notice-wire.d.ts +7 -7
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/injection-tier.d.ts +11 -21
- package/dist/trace/injection-tier.js +3 -4
- package/dist/trace/ledger-events.d.ts +3 -3
- package/dist/trace/ledger-sink.d.ts +7 -7
- package/dist/trace/project.d.ts +31 -30
- package/dist/trace/project.js +1 -0
- package/dist/turn-activity.d.ts +4 -4
- package/dist/usage-analytics.d.ts +1 -1
- package/dist/wall-clock-jump-guard.d.ts +3 -3
- package/package.json +6 -6
package/dist/tool-approval.js
CHANGED
|
@@ -3,6 +3,7 @@ import { uuidv7, MAX_RULE_TEXT_CHARS } from "@sema-agent/core";
|
|
|
3
3
|
import { precheckCardRuleText } from "./rules-consent.js";
|
|
4
4
|
import { redactDeep, redactSecrets } from "./trace/redact.js";
|
|
5
5
|
import { hasBidiControls } from "./text-bidi.js";
|
|
6
|
+
import { approvalPayloadFingerprint } from "./plugins/approval-payload-fingerprint.js";
|
|
6
7
|
import { createLogger } from "./observability/logger.js";
|
|
7
8
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
8
9
|
import { deriveAskId, deriveBatchId, MAX_DECISION_NOTE_CHARS } from "./approval-ask-machine.js";
|
|
@@ -45,6 +46,20 @@ export const ASK_DECISION_CONSUMER_ABSENT = "absent";
|
|
|
45
46
|
const DURABLE_CONVERGE_BACKOFF_MS = [50, 100, 200, 400, 800, 1600];
|
|
46
47
|
const DURABLE_CONVERGE_READ_TIMEOUT_MS = 2_000;
|
|
47
48
|
const DURABLE_CALL_TIMEOUT_MS = 5_000;
|
|
49
|
+
function ambiguousCasFailOpenTag(intent) {
|
|
50
|
+
switch (intent) {
|
|
51
|
+
case "expire":
|
|
52
|
+
return "server.approval.ambiguous-cas.expire";
|
|
53
|
+
case "cancel":
|
|
54
|
+
return "server.approval.ambiguous-cas.cancel";
|
|
55
|
+
case "unreachable":
|
|
56
|
+
return "server.approval.ambiguous-cas.unreachable";
|
|
57
|
+
default: {
|
|
58
|
+
const unreachable = intent;
|
|
59
|
+
throw new Error(`ambiguousCasFailOpenTag: unknown intent ${String(unreachable)}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
48
63
|
class ApprovalStoreDeadlineError extends Error {
|
|
49
64
|
constructor(label, timeoutMs) {
|
|
50
65
|
super(`approval store call ${label} timed out after ${timeoutMs}ms`);
|
|
@@ -194,14 +209,21 @@ function effectiveAskWindowMs(ttlMs, windowMarginMs, legDeadlineMonotonic, nowMo
|
|
|
194
209
|
return Math.min(ttlMs, Math.max(0, legRemainingMs - windowMarginMs));
|
|
195
210
|
}
|
|
196
211
|
function replayTerminalAskRow(row) {
|
|
197
|
-
if (row.state === "DECIDED")
|
|
198
|
-
|
|
212
|
+
if (row.state === "DECIDED") {
|
|
213
|
+
if (row.decision !== "approve")
|
|
214
|
+
return false;
|
|
215
|
+
return row.updatedInput !== undefined ? { allow: true, updatedInput: row.updatedInput } : true;
|
|
216
|
+
}
|
|
199
217
|
if (row.state === "PARKING" || row.state === "PARKED")
|
|
200
218
|
return "unavailable";
|
|
201
219
|
return false;
|
|
202
220
|
}
|
|
203
|
-
function
|
|
204
|
-
|
|
221
|
+
function settleArgsOf(outcome) {
|
|
222
|
+
if (outcome === "unavailable")
|
|
223
|
+
return "unavailable";
|
|
224
|
+
if (typeof outcome === "boolean")
|
|
225
|
+
return { allowed: outcome };
|
|
226
|
+
return { allowed: outcome.allow, ...(outcome.updatedInput !== undefined ? { updatedInput: outcome.updatedInput } : {}) };
|
|
205
227
|
}
|
|
206
228
|
export class ToolApprovalCoordinator {
|
|
207
229
|
als = new AsyncLocalStorage();
|
|
@@ -432,26 +454,32 @@ export class ToolApprovalCoordinator {
|
|
|
432
454
|
return false;
|
|
433
455
|
}
|
|
434
456
|
}
|
|
435
|
-
async
|
|
457
|
+
async readRowForRecovery(askId, where) {
|
|
436
458
|
if (!this.askStore)
|
|
437
|
-
return
|
|
459
|
+
return { kind: "absent" };
|
|
460
|
+
let row;
|
|
438
461
|
try {
|
|
439
|
-
|
|
440
|
-
if (row === null || row.state !== "DECIDED")
|
|
441
|
-
return undefined;
|
|
442
|
-
if (replayTerminalAskRow(row) === true && this.abandonedEditedDecisionPending(askId)) {
|
|
443
|
-
this.guardRowDerivedApprove(askId, true, "expire-error-recovery");
|
|
444
|
-
return undefined;
|
|
445
|
-
}
|
|
446
|
-
if (this.editedDecisionInFlight(askId))
|
|
447
|
-
return undefined;
|
|
448
|
-
const replayed = replayTerminalAskRow(row);
|
|
449
|
-
return typeof replayed === "boolean" ? replayed : undefined;
|
|
462
|
+
row = await this.withStoreDeadline(this.askStore.getAsk(askId), `getAsk(${where})`, DURABLE_CONVERGE_READ_TIMEOUT_MS);
|
|
450
463
|
}
|
|
451
464
|
catch (err) {
|
|
452
|
-
this.noteStoreError(err,
|
|
453
|
-
return
|
|
465
|
+
this.noteStoreError(err, `getAsk(${where})`);
|
|
466
|
+
return { kind: "unreadable" };
|
|
454
467
|
}
|
|
468
|
+
if (row === null)
|
|
469
|
+
return { kind: "absent" };
|
|
470
|
+
if (row.state === "STREAM_PENDING") {
|
|
471
|
+
return this.editedDecisionInFlight(askId) ? { kind: "edit-in-flight" } : { kind: "pending" };
|
|
472
|
+
}
|
|
473
|
+
const replayed = settleArgsOf(this.guardRowDerivedApprove(askId, replayTerminalAskRow(row), where));
|
|
474
|
+
if (replayed === "unavailable")
|
|
475
|
+
return { kind: "parked" };
|
|
476
|
+
if (!replayed.allowed)
|
|
477
|
+
return { kind: "denied" };
|
|
478
|
+
if (replayed.updatedInput !== undefined)
|
|
479
|
+
return { kind: "approved", updatedInput: replayed.updatedInput };
|
|
480
|
+
if (this.editedDecisionInFlight(askId))
|
|
481
|
+
return { kind: "edit-in-flight" };
|
|
482
|
+
return { kind: "approved" };
|
|
455
483
|
}
|
|
456
484
|
hasOtherSuspendedOwner(askId, self) {
|
|
457
485
|
if (askId === undefined)
|
|
@@ -482,13 +510,17 @@ export class ToolApprovalCoordinator {
|
|
|
482
510
|
const now = Date.now();
|
|
483
511
|
let ownCount = 0;
|
|
484
512
|
let ownExpiredVictim;
|
|
513
|
+
let ownBridgeVictim;
|
|
485
514
|
let ownPlainVictim;
|
|
486
515
|
let ownEvictable;
|
|
487
516
|
let globalExpiredVictim;
|
|
517
|
+
let globalBridgeVictim;
|
|
488
518
|
for (const [k, t] of this.parkTombstones) {
|
|
489
519
|
const expired = now - t.parkedAtMs > this.parkTombstoneTtlMs;
|
|
490
520
|
if (globalExpiredVictim === undefined && expired && t.inflight === undefined)
|
|
491
521
|
globalExpiredVictim = k;
|
|
522
|
+
if (globalBridgeVictim === undefined && t.kind === "voidBridge" && t.inflight === undefined)
|
|
523
|
+
globalBridgeVictim = k;
|
|
492
524
|
if (t.owner !== tomb.owner)
|
|
493
525
|
continue;
|
|
494
526
|
ownCount++;
|
|
@@ -498,13 +530,16 @@ export class ToolApprovalCoordinator {
|
|
|
498
530
|
ownEvictable = k;
|
|
499
531
|
if (ownExpiredVictim === undefined && expired)
|
|
500
532
|
ownExpiredVictim = k;
|
|
501
|
-
if (
|
|
533
|
+
if (ownBridgeVictim === undefined && t.kind === "voidBridge")
|
|
534
|
+
ownBridgeVictim = k;
|
|
535
|
+
if (ownPlainVictim === undefined && t.kind === "park" && t.redeemed === undefined)
|
|
502
536
|
ownPlainVictim = k;
|
|
503
537
|
}
|
|
538
|
+
const insertingBridge = tomb.kind === "voidBridge";
|
|
504
539
|
if (ownCount >= effectivePerPrincipalMax) {
|
|
505
|
-
const victim = ownExpiredVictim ?? ownPlainVictim ?? ownEvictable;
|
|
540
|
+
const victim = insertingBridge ? (ownExpiredVictim ?? ownBridgeVictim) : (ownExpiredVictim ?? ownBridgeVictim ?? ownPlainVictim ?? ownEvictable);
|
|
506
541
|
if (victim === undefined) {
|
|
507
|
-
recordFailOpen("server.approval.park-tombstone-global-cap-refused", `owner=${tomb.owner ?? "<none>"} reason
|
|
542
|
+
recordFailOpen("server.approval.park-tombstone-global-cap-refused", `owner=${tomb.owner ?? "<none>"} reason=${insertingBridge ? "bridge-would-evict-redeemable" : "all-inflight"}`);
|
|
508
543
|
return;
|
|
509
544
|
}
|
|
510
545
|
this.parkTombstones.delete(victim);
|
|
@@ -512,8 +547,11 @@ export class ToolApprovalCoordinator {
|
|
|
512
547
|
else if (this.parkTombstones.size >= this.parkTombstoneMax && globalExpiredVictim !== undefined) {
|
|
513
548
|
this.parkTombstones.delete(globalExpiredVictim);
|
|
514
549
|
}
|
|
550
|
+
else if (this.parkTombstones.size >= this.parkTombstoneMax && !insertingBridge && globalBridgeVictim !== undefined) {
|
|
551
|
+
this.parkTombstones.delete(globalBridgeVictim);
|
|
552
|
+
}
|
|
515
553
|
else if (this.parkTombstones.size >= this.parkTombstoneMax) {
|
|
516
|
-
recordFailOpen("server.approval.park-tombstone-global-cap-refused", `owner=${tomb.owner ?? "<none>"}`);
|
|
554
|
+
recordFailOpen("server.approval.park-tombstone-global-cap-refused", `owner=${tomb.owner ?? "<none>"}${insertingBridge ? " reason=bridge-refused-at-global-cap" : ""}`);
|
|
517
555
|
return;
|
|
518
556
|
}
|
|
519
557
|
this.parkTombstones.set(approvalId, tomb);
|
|
@@ -745,8 +783,6 @@ export class ToolApprovalCoordinator {
|
|
|
745
783
|
if (existingOrCreated.row.state !== "STREAM_PENDING") {
|
|
746
784
|
releaseAdmission();
|
|
747
785
|
const replayed = this.guardRowDerivedApprove(askId, replayTerminalAskRow(existingOrCreated.row), "ensure-ask-idempotent-replay");
|
|
748
|
-
if (replayed === true)
|
|
749
|
-
recordRowDerivedApproveReplay("ensure-ask-idempotent-replay");
|
|
750
786
|
return replayed === "unavailable" ? this.unattendedOutcome() : replayed;
|
|
751
787
|
}
|
|
752
788
|
const persistedEnvelope = ApprovalCardEnvelopeSchema.safeParse(existingOrCreated.row.cardJson);
|
|
@@ -872,7 +908,7 @@ export class ToolApprovalCoordinator {
|
|
|
872
908
|
sig.removeEventListener("abort", fn);
|
|
873
909
|
this.pending.delete(id);
|
|
874
910
|
if (windowRouteUnavailable && askId !== undefined && batchId !== undefined && this.unattendedOutcome() !== false) {
|
|
875
|
-
this.recordParkTombstone(wireApprovalId, { askId, batchId, owner: origin.owner, parkedAtMs: Date.now() });
|
|
911
|
+
this.recordParkTombstone(wireApprovalId, { kind: "park", askId, batchId, owner: origin.owner, parkedAtMs: Date.now() });
|
|
876
912
|
parkRouted = true;
|
|
877
913
|
}
|
|
878
914
|
if (askId !== undefined) {
|
|
@@ -892,40 +928,37 @@ export class ToolApprovalCoordinator {
|
|
|
892
928
|
const convergeFromDurableState = async (where) => {
|
|
893
929
|
if (!this.askStore || askId === undefined)
|
|
894
930
|
return;
|
|
895
|
-
const store = this.askStore;
|
|
896
931
|
const pinnedAskId = askId;
|
|
897
|
-
for (let attempt = 0; attempt
|
|
932
|
+
for (let attempt = 0; attempt <= DURABLE_CONVERGE_BACKOFF_MS.length; attempt++) {
|
|
898
933
|
if (done)
|
|
899
934
|
return;
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
935
|
+
const read = await this.readRowForRecovery(pinnedAskId, `converge:${where}`);
|
|
936
|
+
if (done)
|
|
937
|
+
return;
|
|
938
|
+
switch (read.kind) {
|
|
939
|
+
case "absent":
|
|
905
940
|
settle(false, "expired");
|
|
906
941
|
return;
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
942
|
+
case "pending":
|
|
943
|
+
case "edit-in-flight":
|
|
944
|
+
case "unreadable":
|
|
945
|
+
if (attempt < DURABLE_CONVERGE_BACKOFF_MS.length)
|
|
946
|
+
await new Promise((r) => setTimeout(r, DURABLE_CONVERGE_BACKOFF_MS[attempt]).unref?.());
|
|
910
947
|
continue;
|
|
911
|
-
|
|
912
|
-
const outcome = this.guardRowDerivedApprove(pinnedAskId, replayTerminalAskRow(row), `converge:${where}`);
|
|
913
|
-
if (outcome === "unavailable") {
|
|
948
|
+
case "parked":
|
|
914
949
|
windowRouteUnavailable = true;
|
|
915
950
|
settle(false, "expired");
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
else {
|
|
951
|
+
return;
|
|
952
|
+
case "approved":
|
|
953
|
+
settle(true, "allowed", read.updatedInput);
|
|
954
|
+
return;
|
|
955
|
+
case "denied":
|
|
922
956
|
settle(false, "denied");
|
|
957
|
+
return;
|
|
958
|
+
default: {
|
|
959
|
+
const unreachable = read;
|
|
960
|
+
throw new Error(`convergeFromDurableState: unknown recovery read ${String(unreachable)}`);
|
|
923
961
|
}
|
|
924
|
-
return;
|
|
925
|
-
}
|
|
926
|
-
catch (err) {
|
|
927
|
-
this.noteStoreError(err, `getAsk(${where})`);
|
|
928
|
-
await new Promise((r) => setTimeout(r, DURABLE_CONVERGE_BACKOFF_MS[attempt]).unref?.());
|
|
929
962
|
}
|
|
930
963
|
}
|
|
931
964
|
if (!done) {
|
|
@@ -938,6 +971,90 @@ export class ToolApprovalCoordinator {
|
|
|
938
971
|
}
|
|
939
972
|
}
|
|
940
973
|
};
|
|
974
|
+
const recoverFromUnknownStore = async (arm, casStillInFlight) => {
|
|
975
|
+
if (askId === undefined) {
|
|
976
|
+
arm.settleByIntent();
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
const pinnedAskId = askId;
|
|
980
|
+
for (let attempt = 0; attempt <= DURABLE_CONVERGE_BACKOFF_MS.length; attempt++) {
|
|
981
|
+
if (done)
|
|
982
|
+
return;
|
|
983
|
+
const read = await this.readRowForRecovery(pinnedAskId, `recovery:${arm.intent}`);
|
|
984
|
+
if (done)
|
|
985
|
+
return;
|
|
986
|
+
switch (read.kind) {
|
|
987
|
+
case "approved":
|
|
988
|
+
settle(true, "allowed", read.updatedInput);
|
|
989
|
+
return;
|
|
990
|
+
case "denied":
|
|
991
|
+
settle(false, "denied");
|
|
992
|
+
return;
|
|
993
|
+
case "parked":
|
|
994
|
+
windowRouteUnavailable = true;
|
|
995
|
+
settle(false, "expired");
|
|
996
|
+
return;
|
|
997
|
+
case "pending": {
|
|
998
|
+
if (casStillInFlight) {
|
|
999
|
+
arm.settleByIntent();
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
let result;
|
|
1003
|
+
try {
|
|
1004
|
+
result = await arm.cas();
|
|
1005
|
+
}
|
|
1006
|
+
catch (err) {
|
|
1007
|
+
this.noteStoreError(err, arm.storeLabel);
|
|
1008
|
+
arm.settleByIntent();
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
1011
|
+
if (arm.won(result)) {
|
|
1012
|
+
arm.onWon(result);
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
await convergeFromDurableState(arm.where);
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1018
|
+
case "absent":
|
|
1019
|
+
arm.settleByIntent();
|
|
1020
|
+
return;
|
|
1021
|
+
case "edit-in-flight":
|
|
1022
|
+
case "unreadable":
|
|
1023
|
+
if (attempt < DURABLE_CONVERGE_BACKOFF_MS.length)
|
|
1024
|
+
await new Promise((r) => setTimeout(r, DURABLE_CONVERGE_BACKOFF_MS[attempt]).unref?.());
|
|
1025
|
+
continue;
|
|
1026
|
+
default: {
|
|
1027
|
+
const unreachable = read;
|
|
1028
|
+
throw new Error(`recoverFromUnknownStore: unknown recovery read ${String(unreachable)}`);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
if (done)
|
|
1033
|
+
return;
|
|
1034
|
+
if (this.editedDecisionInFlight(pinnedAskId)) {
|
|
1035
|
+
windowRouteUnavailable = true;
|
|
1036
|
+
settle(false, "expired");
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
1039
|
+
recordFailOpen(ambiguousCasFailOpenTag(arm.intent), `askId=${pinnedAskId} reads=${DURABLE_CONVERGE_BACKOFF_MS.length + 1}`);
|
|
1040
|
+
arm.settleByIntent();
|
|
1041
|
+
};
|
|
1042
|
+
const resolveLocalOutcome = async (arm) => {
|
|
1043
|
+
let result;
|
|
1044
|
+
try {
|
|
1045
|
+
result = await arm.cas();
|
|
1046
|
+
}
|
|
1047
|
+
catch (err) {
|
|
1048
|
+
this.noteStoreError(err, arm.storeLabel);
|
|
1049
|
+
await recoverFromUnknownStore(arm, err instanceof ApprovalStoreDeadlineError);
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
if (arm.won(result)) {
|
|
1053
|
+
arm.onWon(result);
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
await convergeFromDurableState(arm.where);
|
|
1057
|
+
};
|
|
941
1058
|
const settleParkRouteIfUnsettled = (hostSettledBy) => {
|
|
942
1059
|
if (done)
|
|
943
1060
|
return;
|
|
@@ -950,36 +1067,30 @@ export class ToolApprovalCoordinator {
|
|
|
950
1067
|
settleParkRouteIfUnsettled(hostSelfReport);
|
|
951
1068
|
return;
|
|
952
1069
|
}
|
|
953
|
-
|
|
954
|
-
|
|
1070
|
+
const store = this.askStore;
|
|
1071
|
+
const pinnedAskId = askId;
|
|
1072
|
+
const pinnedBatchId = batchId;
|
|
1073
|
+
await resolveLocalOutcome({
|
|
1074
|
+
intent: "expire",
|
|
1075
|
+
storeLabel: "expireAsk",
|
|
1076
|
+
where: "windowExpired",
|
|
1077
|
+
cas: () => this.withStoreDeadline(store.expireAsk(pinnedAskId, pinnedBatchId), "expireAsk(window)", DURABLE_CALL_TIMEOUT_MS, (late) => {
|
|
955
1078
|
if (!late.won)
|
|
956
1079
|
return;
|
|
957
|
-
this.settleSameAskIdParkRoute(
|
|
1080
|
+
this.settleSameAskIdParkRoute(pinnedAskId);
|
|
958
1081
|
this.settleVoidedSiblings(late.voidedSiblings);
|
|
959
|
-
this.emitRevokeTo(aliveCtxs, buildRevokeFrame(
|
|
960
|
-
})
|
|
961
|
-
|
|
1082
|
+
this.emitRevokeTo(aliveCtxs, buildRevokeFrame(pinnedBatchId, late.voidedSiblings, "superseded_by_park", Date.now()));
|
|
1083
|
+
}),
|
|
1084
|
+
won: (res) => res.won,
|
|
1085
|
+
onWon: (res) => {
|
|
962
1086
|
windowRouteUnavailable = true;
|
|
963
1087
|
settle(false, "expired");
|
|
964
|
-
this.settleSameAskIdParkRoute(
|
|
1088
|
+
this.settleSameAskIdParkRoute(pinnedAskId);
|
|
965
1089
|
this.settleVoidedSiblings(res.voidedSiblings);
|
|
966
|
-
this.emitRevokeTo(aliveCtxs, buildRevokeFrame(
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
catch (err) {
|
|
973
|
-
this.noteStoreError(err, "expireAsk");
|
|
974
|
-
const decided = await this.readDecidedForRecovery(askId);
|
|
975
|
-
if (decided !== undefined && !done) {
|
|
976
|
-
if (decided)
|
|
977
|
-
recordRowDerivedApproveReplay("expire-error-recovery");
|
|
978
|
-
settle(decided, decided ? "allowed" : "denied");
|
|
979
|
-
return;
|
|
980
|
-
}
|
|
981
|
-
settleParkRouteIfUnsettled(hostSelfReport);
|
|
982
|
-
}
|
|
1090
|
+
this.emitRevokeTo(aliveCtxs, buildRevokeFrame(pinnedBatchId, res.voidedSiblings, "superseded_by_park", Date.now()));
|
|
1091
|
+
},
|
|
1092
|
+
settleByIntent: () => settleParkRouteIfUnsettled(hostSelfReport),
|
|
1093
|
+
});
|
|
983
1094
|
})();
|
|
984
1095
|
};
|
|
985
1096
|
const forceParkNow = () => {
|
|
@@ -1002,26 +1113,29 @@ export class ToolApprovalCoordinator {
|
|
|
1002
1113
|
settle(false, "expired");
|
|
1003
1114
|
return;
|
|
1004
1115
|
}
|
|
1005
|
-
|
|
1006
|
-
|
|
1116
|
+
const store = this.askStore;
|
|
1117
|
+
const pinnedAskId = askId;
|
|
1118
|
+
const pinnedBatchId = batchId;
|
|
1119
|
+
await resolveLocalOutcome({
|
|
1120
|
+
intent: "cancel",
|
|
1121
|
+
storeLabel: "transitionAsk(cancel)",
|
|
1122
|
+
where: "runCancel",
|
|
1123
|
+
cas: () => this.withStoreDeadline(store.transitionAsk(pinnedAskId, "STREAM_PENDING", "VOID", { updatedAtMs: Date.now() }), "transitionAsk(cancel)", DURABLE_CALL_TIMEOUT_MS, (lateWon) => {
|
|
1007
1124
|
if (!lateWon)
|
|
1008
1125
|
return;
|
|
1009
|
-
this.settleVoidedSiblings([
|
|
1010
|
-
this.
|
|
1011
|
-
|
|
1012
|
-
|
|
1126
|
+
this.settleVoidedSiblings([pinnedAskId]);
|
|
1127
|
+
this.recordParkTombstone(wireApprovalId, { kind: "voidBridge", askId: pinnedAskId, batchId: pinnedBatchId, owner: origin.owner, parkedAtMs: Date.now() });
|
|
1128
|
+
this.emitRevokeTo(aliveCtxs, buildRevokeFrame(pinnedBatchId, [pinnedAskId], "aborted", Date.now()));
|
|
1129
|
+
}),
|
|
1130
|
+
won: (won) => won,
|
|
1131
|
+
onWon: () => {
|
|
1013
1132
|
settle(false, "expired");
|
|
1014
|
-
this.settleVoidedSiblings([
|
|
1015
|
-
this.
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
}
|
|
1021
|
-
catch (err) {
|
|
1022
|
-
this.noteStoreError(err, "transitionAsk(cancel)");
|
|
1023
|
-
settle(false, "expired");
|
|
1024
|
-
}
|
|
1133
|
+
this.settleVoidedSiblings([pinnedAskId]);
|
|
1134
|
+
this.recordParkTombstone(wireApprovalId, { kind: "voidBridge", askId: pinnedAskId, batchId: pinnedBatchId, owner: origin.owner, parkedAtMs: Date.now() });
|
|
1135
|
+
this.emitRevokeTo(aliveCtxs, buildRevokeFrame(pinnedBatchId, [pinnedAskId], "aborted", Date.now()));
|
|
1136
|
+
},
|
|
1137
|
+
settleByIntent: () => settle(false, "expired"),
|
|
1138
|
+
});
|
|
1025
1139
|
};
|
|
1026
1140
|
if (signal) {
|
|
1027
1141
|
const onTaskAbort = () => void runCancel();
|
|
@@ -1111,31 +1225,42 @@ export class ToolApprovalCoordinator {
|
|
|
1111
1225
|
const emitAllP = (async () => {
|
|
1112
1226
|
const results = await Promise.all(openByCtx.values());
|
|
1113
1227
|
const anySucceeded = reachability === "unreached" || this.hasOtherSuspendedOwner(askId, selfEntry) || results.some((r) => r.legacy || r.card);
|
|
1228
|
+
emitSettled = true;
|
|
1114
1229
|
if (!anySucceeded && !done) {
|
|
1115
1230
|
if (this.askStore && askId !== undefined && batchId !== undefined) {
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1231
|
+
const store = this.askStore;
|
|
1232
|
+
const pinnedAskId = askId;
|
|
1233
|
+
const pinnedBatchId = batchId;
|
|
1234
|
+
const settleUnreachable = () => {
|
|
1235
|
+
if (done)
|
|
1236
|
+
return;
|
|
1237
|
+
emitFailed = true;
|
|
1238
|
+
settle(false, "expired");
|
|
1239
|
+
};
|
|
1240
|
+
await resolveLocalOutcome({
|
|
1241
|
+
intent: "unreachable",
|
|
1242
|
+
storeLabel: "expireAsk(emit-failed)",
|
|
1243
|
+
where: "emitFailed",
|
|
1244
|
+
cas: () => this.withStoreDeadline(store.expireAsk(pinnedAskId, pinnedBatchId), "expireAsk(emit-failed)", DURABLE_CALL_TIMEOUT_MS, (late) => {
|
|
1245
|
+
if (!late.won)
|
|
1246
|
+
return;
|
|
1247
|
+
this.settleSameAskIdParkRoute(pinnedAskId);
|
|
1248
|
+
this.settleVoidedSiblings(late.voidedSiblings);
|
|
1249
|
+
}),
|
|
1250
|
+
won: (res) => res.won,
|
|
1251
|
+
onWon: (res) => {
|
|
1252
|
+
settleUnreachable();
|
|
1253
|
+
this.settleSameAskIdParkRoute(pinnedAskId);
|
|
1122
1254
|
this.settleVoidedSiblings(res.voidedSiblings);
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
this.noteStoreError(err, "expireAsk(emit-failed)");
|
|
1127
|
-
if (!done) {
|
|
1128
|
-
emitFailed = true;
|
|
1129
|
-
settle(false, "expired");
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1255
|
+
},
|
|
1256
|
+
settleByIntent: settleUnreachable,
|
|
1257
|
+
});
|
|
1132
1258
|
}
|
|
1133
1259
|
else if (!done) {
|
|
1134
1260
|
emitFailed = true;
|
|
1135
1261
|
settle(false, "expired");
|
|
1136
1262
|
}
|
|
1137
1263
|
}
|
|
1138
|
-
emitSettled = true;
|
|
1139
1264
|
})();
|
|
1140
1265
|
await Promise.race([emitAllP, allowedP]);
|
|
1141
1266
|
const settled = await allowedP;
|
|
@@ -1288,9 +1413,7 @@ export class ToolApprovalCoordinator {
|
|
|
1288
1413
|
});
|
|
1289
1414
|
return this.notPending();
|
|
1290
1415
|
}
|
|
1291
|
-
|
|
1292
|
-
if (row.decision === "approve" && settled.settled > 0)
|
|
1293
|
-
recordRowDerivedApproveReplay("respond-late-replay");
|
|
1416
|
+
this.notifyExternalDecision(row.askId, row.decision === "approve", row.updatedInput);
|
|
1294
1417
|
return {
|
|
1295
1418
|
status: 200,
|
|
1296
1419
|
body: {
|
|
@@ -1559,11 +1682,13 @@ export class ToolApprovalCoordinator {
|
|
|
1559
1682
|
}
|
|
1560
1683
|
async respondWithCas(askStore, askId, batchId, id, entry, parsed, ruleEligibility) {
|
|
1561
1684
|
let decidedWon = false;
|
|
1685
|
+
let confirmedRowPayload;
|
|
1562
1686
|
let noteLanded = false;
|
|
1563
1687
|
try {
|
|
1564
1688
|
const decided = await this.withStoreDeadline(askStore.decideAsk(askId, batchId, {
|
|
1565
1689
|
decision: parsed.value === "deny" ? "deny" : "approve",
|
|
1566
1690
|
...(parsed.note !== undefined ? { decisionNote: parsed.note } : {}),
|
|
1691
|
+
...(parsed.value !== "deny" && parsed.updatedInput !== undefined ? { updatedInput: parsed.updatedInput } : {}),
|
|
1567
1692
|
}), "decideAsk", DURABLE_CALL_TIMEOUT_MS, (late) => {
|
|
1568
1693
|
if (late.ok)
|
|
1569
1694
|
this.notifyExternalDecision(askId, parsed.value !== "deny", parsed.updatedInput);
|
|
@@ -1582,6 +1707,7 @@ export class ToolApprovalCoordinator {
|
|
|
1582
1707
|
const row = await this.withStoreDeadline(askStore.getAsk(askId), "getAsk(decideAsk-confirm)", DURABLE_CONVERGE_READ_TIMEOUT_MS);
|
|
1583
1708
|
if (row?.state === "DECIDED" && row.decision === (parsed.value === "deny" ? "deny" : "approve")) {
|
|
1584
1709
|
decidedWon = true;
|
|
1710
|
+
confirmedRowPayload = { updatedInput: row.updatedInput };
|
|
1585
1711
|
noteLanded = parsed.note === undefined || row.decisionNote === parsed.note;
|
|
1586
1712
|
}
|
|
1587
1713
|
}
|
|
@@ -1592,15 +1718,20 @@ export class ToolApprovalCoordinator {
|
|
|
1592
1718
|
const wantAllowed = parsed.value !== "deny";
|
|
1593
1719
|
if (this.pending.get(id) !== entry) {
|
|
1594
1720
|
if (decidedWon)
|
|
1595
|
-
this.notifyExternalDecision(askId, wantAllowed, parsed.updatedInput);
|
|
1721
|
+
this.notifyExternalDecision(askId, wantAllowed, confirmedRowPayload !== undefined ? confirmedRowPayload.updatedInput : parsed.updatedInput);
|
|
1596
1722
|
const converged = decidedWon && entry.settledOutcome === (wantAllowed ? "allowed" : "denied");
|
|
1597
1723
|
if (!converged) {
|
|
1598
1724
|
return this.notPending();
|
|
1599
1725
|
}
|
|
1600
1726
|
return this.finishRespond(id, entry, parsed, { updatedInputDelivered: false, noteRecorded: noteLanded });
|
|
1601
1727
|
}
|
|
1602
|
-
const
|
|
1603
|
-
|
|
1728
|
+
const payloadIsMine = confirmedRowPayload === undefined ||
|
|
1729
|
+
approvalPayloadFingerprint({ updatedInput: confirmedRowPayload.updatedInput }) === approvalPayloadFingerprint({ updatedInput: parsed.updatedInput });
|
|
1730
|
+
const result = this.finishRespond(id, entry, parsed, {
|
|
1731
|
+
noteRecorded: noteLanded,
|
|
1732
|
+
...(confirmedRowPayload !== undefined ? { settlePayload: confirmedRowPayload, updatedInputDelivered: payloadIsMine } : {}),
|
|
1733
|
+
});
|
|
1734
|
+
this.notifyExternalDecision(askId, wantAllowed, confirmedRowPayload !== undefined ? confirmedRowPayload.updatedInput : parsed.updatedInput);
|
|
1604
1735
|
return result;
|
|
1605
1736
|
}
|
|
1606
1737
|
finishRespond(id, entry, parsed, opts) {
|
|
@@ -1617,7 +1748,7 @@ export class ToolApprovalCoordinator {
|
|
|
1617
1748
|
this.allowAllSessions.add(sessionAllowKey(entry.owner, entry.sessionId, sessionAllowCategory(entry.toolName)));
|
|
1618
1749
|
}
|
|
1619
1750
|
const allowed = parsed.value !== "deny";
|
|
1620
|
-
entry.settle(allowed, allowed ? "allowed" : "denied", parsed.updatedInput, undefined, allowed ? undefined : parsed.note);
|
|
1751
|
+
entry.settle(allowed, allowed ? "allowed" : "denied", opts?.settlePayload !== undefined ? opts.settlePayload.updatedInput : parsed.updatedInput, undefined, allowed ? undefined : parsed.note);
|
|
1621
1752
|
const updatedInputDelivered = opts?.updatedInputDelivered ?? true;
|
|
1622
1753
|
const noteRecorded = opts?.noteRecorded ?? false;
|
|
1623
1754
|
return {
|
|
@@ -1687,18 +1818,14 @@ export class ToolApprovalCoordinator {
|
|
|
1687
1818
|
continue;
|
|
1688
1819
|
if (this.editedDecisionInFlight(askId))
|
|
1689
1820
|
continue;
|
|
1690
|
-
const outcome = replayTerminalAskRow(row);
|
|
1821
|
+
const outcome = settleArgsOf(replayTerminalAskRow(row));
|
|
1691
1822
|
if (outcome === "unavailable") {
|
|
1692
1823
|
const before = this.pendingByAskId.get(askId)?.size ?? 0;
|
|
1693
1824
|
this.settleSameAskIdParkRoute(askId);
|
|
1694
1825
|
settled += before;
|
|
1695
1826
|
continue;
|
|
1696
1827
|
}
|
|
1697
|
-
|
|
1698
|
-
continue;
|
|
1699
|
-
const delivered = this.notifyExternalDecision(askId, outcome).settled;
|
|
1700
|
-
if (outcome && delivered > 0)
|
|
1701
|
-
recordRowDerivedApproveReplay("poll-suspended");
|
|
1828
|
+
const delivered = this.notifyExternalDecision(askId, outcome.allowed, outcome.updatedInput).settled;
|
|
1702
1829
|
settled += delivered;
|
|
1703
1830
|
}
|
|
1704
1831
|
const backlog = Math.max(0, candidates.length - polled);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* L1 键集机器门([
|
|
2
|
+
* L1 键集机器门([ref] 方法论倡议 server 认领件;clay 令 2026-07-23「不能永远编码有限→复审补漏」)。
|
|
3
3
|
*
|
|
4
4
|
* 病族:**投影白名单剥键**——core 给源类型加 additive 新键,server 的列投影/白名单静默丢,直到穿透
|
|
5
|
-
* 审查才被人肉抓。已四案:RosterEntry.model([
|
|
6
|
-
* 四键 / BackgroundChildEvent.usage+transcriptId([
|
|
5
|
+
* 审查才被人肉抓。已四案:RosterEntry.model([ref])、task_progress.status / TaskNotificationPayload
|
|
6
|
+
* 四键 / BackgroundChildEvent.usage+transcriptId([ref] 族B)、SDK 0.0.72 fleet meta 剥键。
|
|
7
7
|
*
|
|
8
8
|
* 机制:对每个「core 源类型 → server 投影」面声明**已处置键集** = PROJECTED(真透传)∪ EXCLUDED
|
|
9
9
|
* (显式记账不透传,理由必写)。`Exclude<keyof 源, 已处置>` 约束为 never——**升 core 后源类型出新键
|
|
@@ -14,8 +14,10 @@
|
|
|
14
14
|
*
|
|
15
15
|
* 维护:core 新键到来时,transparently 透传的加进对应 PROJECTED 并去实现投影;有意不上 wire 的加进
|
|
16
16
|
* EXCLUDED 并写一行理由。谁改投影(project.ts / fleet-bus.ts / roster-store-sql.ts)谁同步本文件。
|
|
17
|
+
* ⑨⑩([ref],2026-08-31)把两个最大的 wire 面也纳入:TaskSpec 按「server 有无写点」记 Wired/Unwired,
|
|
18
|
+
* TaskResult 按「转发/摘除」记 Forwarded/Stripped —— 谁改 resolve-spec.ts / runs.ts 的发射点谁同步本文件。
|
|
17
19
|
*/
|
|
18
|
-
import type { TaskNotificationPayload, BackgroundChildEvent, RosterEntry, AskRequest, CheckpointSummary, TaskEvent, TraceEvent, MailboxMessage, MailboxStore } from "@sema-agent/core";
|
|
20
|
+
import type { TaskNotificationPayload, BackgroundChildEvent, RosterEntry, AskRequest, CheckpointSummary, TaskEvent, TraceEvent, MailboxMessage, MailboxStore, TaskSpec, TaskResult } from "@sema-agent/core";
|
|
19
21
|
/** 编译期断言:T 必须收敛到 never(有残余键 = tsc 红)。 */
|
|
20
22
|
type AssertAllKeysHandled<T extends never> = T;
|
|
21
23
|
type NotificationProjected = "task_id" | "task_type" | "toolUseId" | "status" | "summary" | "result" | "output_file" | "usage" | "sessionId" | "seq" | "lines" | "stoppedBy" | "source" | "exitCode" | "partial" | "diagnostics" | "recentSteps" | "editedFiles" | "resumable" | "completionId" | "error" | "errorCode" | "apiFailure";
|
|
@@ -47,6 +49,14 @@ type _GuardPermissionTraceNonEmpty = AssertAllKeysHandled<AssertNonEmpty<Permiss
|
|
|
47
49
|
type SummaryProjected = "sessionId" | "scope" | "createdAt" | "gateKind" | "severity" | "spentMicroUsd" | "deadline" | "hasBidiControls";
|
|
48
50
|
type SummaryExcluded = "token" | "toolInput" | "toolName" | "toolCallId" | "preview" | "principal" | "sourceTaskId" | "contentKind" | "restoreMode" | "checkpointId" | "previewWithheld";
|
|
49
51
|
type _GuardInboxSummary = AssertAllKeysHandled<Exclude<keyof CheckpointSummary, SummaryProjected | SummaryExcluded>>;
|
|
52
|
+
type TaskSpecWired = "objective" | "principal" | "images" | "sessionId" | "requireExistingSession" | "oneShot" | "clientContext" | "resumeAt" | "resumeAtMode" | "model" | "compactionModel" | "thinking" | "systemPrompt" | "appendSystemPrompt" | "promptProvider" | "memory" | "suggestNextPrompts" | "restoreFiles" | "acceptPartialRestore" | "rewindFilesTo" | "tools" | "excludeTools" | "deferTools" | "toolMaterializeStrategy" | "promptProfile" | "toolPolicy" | "onAsk" | "onQuestion" | "hooks" | "durableApproval" | "resourceSuspend" | "resilience" | "finalVerification" | "checkpointStore" | "handsReadOnly" | "memoryPersistenceCapable" | "additionalDirectories" | "additionalReadDirectories" | "enablePlanMode" | "interactiveTools" | "enableFork" | "shellGate" | "mcp" | "a2a" | "skills" | "backgroundScope" | "envFacts" | "limits" | "configOverrides" | "forwardSubagentEvents" | "retainSubagentSessions" | "retainBackgroundProcesses" | "outputSchema" | "outputRetries" | "compaction" | "attachments" | "selfOrchestration" | "getApiKeyAndHeaders" | "interactionPosture" | "agents" | "taskId" | "signal" | "preemptSignal" | "modelRole" | "enableBlockedReport" | "maxSuspends";
|
|
53
|
+
type TaskSpecUnwired = "actor" | "roles" | "lspManager" | "tracer" | "readFace" | "readDenyPatterns" | "interactiveQuestionFallback" | "alwaysLoadTools" | "restoreGatedTools" | "deferSelfResolve" | "basePolicyForResumeEdit" | "lspDiagnostics" | "streamingToolExecution" | "toolResultThresholdChars";
|
|
54
|
+
type _GuardTaskSpec = AssertAllKeysHandled<Exclude<keyof TaskSpec, TaskSpecWired | TaskSpecUnwired>>;
|
|
55
|
+
type _GuardTaskSpecReverse = AssertAllKeysHandled<Exclude<TaskSpecWired | TaskSpecUnwired, keyof TaskSpec>>;
|
|
56
|
+
type TaskResultForwarded = "taskId" | "runId" | "sessionId" | "status" | "model" | "effectiveReasoning" | "result" | "salvagedOutput" | "blockedReason" | "checkpointId" | "checkpointGate" | "workspaceRestoreMode" | "remoteEnvFailures" | "errorMessage" | "errorCode" | "apiFailure" | "retryAfterMs" | "degraded" | "structuredOutput" | "rewindNotes" | "haltedOnUserRejection" | "haltedByUser" | "strandedHumanAnswers" | "pendingApproval" | "approvalWaitedMs" | "effectiveReadFace" | "effectiveReadDenyPatterns" | "effectiveMemoryScopes" | "stats";
|
|
57
|
+
type TaskResultStripped = "checkpointToken";
|
|
58
|
+
type _GuardTaskResult = AssertAllKeysHandled<Exclude<keyof TaskResult, TaskResultForwarded | TaskResultStripped>>;
|
|
59
|
+
type _GuardTaskResultReverse = AssertAllKeysHandled<Exclude<TaskResultForwarded | TaskResultStripped, keyof TaskResult>>;
|
|
50
60
|
export type CoreKeysetGuards = [
|
|
51
61
|
_GuardNotification,
|
|
52
62
|
_GuardBgNotif,
|
|
@@ -58,7 +68,11 @@ export type CoreKeysetGuards = [
|
|
|
58
68
|
_GuardPermissionTrace,
|
|
59
69
|
_GuardPermissionTraceReverse,
|
|
60
70
|
_GuardPermissionTraceNonEmpty,
|
|
61
|
-
_GuardInboxSummary
|
|
71
|
+
_GuardInboxSummary,
|
|
72
|
+
_GuardTaskSpec,
|
|
73
|
+
_GuardTaskSpecReverse,
|
|
74
|
+
_GuardTaskResult,
|
|
75
|
+
_GuardTaskResultReverse
|
|
62
76
|
];
|
|
63
77
|
export {};
|
|
64
78
|
//# sourceMappingURL=core-keyset-guard.d.ts.map
|