@sema-agent/core 7.54.1 → 7.55.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/CHANGELOG.md +437 -0
- package/dist/agents/agent-transcript-tool.js +2 -1
- package/dist/agents/builtin-agents.d.ts +12 -14
- package/dist/agents/cc-peer-directory.d.ts +36 -0
- package/dist/agents/cc-peer-directory.js +138 -0
- package/dist/agents/cc-peer-wire.d.ts +105 -0
- package/dist/agents/cc-peer-wire.js +98 -0
- package/dist/agents/cc-uds-peer-channel.d.ts +40 -0
- package/dist/agents/cc-uds-peer-channel.js +457 -0
- package/dist/agents/cross-session-envelope.d.ts +4 -1
- package/dist/agents/cross-session-envelope.js +8 -1
- package/dist/agents/cross-session-judge.d.ts +2 -2
- package/dist/agents/list-agents-tool.js +2 -1
- package/dist/agents/observer.d.ts +4 -5
- package/dist/agents/observer.js +2 -1
- package/dist/agents/peer-admission.d.ts +6 -0
- package/dist/agents/peer-admission.js +4 -1
- package/dist/agents/peer-directory.d.ts +43 -9
- package/dist/agents/peer-directory.js +66 -23
- package/dist/agents/peer-notices.d.ts +1 -1
- package/dist/agents/peer-session-drain.d.ts +3 -1
- package/dist/agents/peer-session-drain.js +1 -0
- package/dist/agents/read-inbox-tool.js +2 -1
- package/dist/agents/retain-ledger.d.ts +1 -1
- package/dist/agents/roster-store.d.ts +1 -1
- package/dist/agents/send-message-tool.d.ts +10 -0
- package/dist/agents/send-message-tool.js +34 -5
- package/dist/agents/subagent.d.ts +34 -79
- package/dist/agents/subagent.js +45 -46
- package/dist/agents/tool-filter.d.ts +29 -46
- package/dist/agents/tool-filter.js +8 -31
- package/dist/agents/verify.d.ts +3 -3
- package/dist/brain/anthropic.js +14 -9
- package/dist/brain/errors.d.ts +15 -0
- package/dist/brain/errors.js +10 -0
- package/dist/brain/model-presets.d.ts +4 -4
- package/dist/brain/open-responses.js +15 -10
- package/dist/brain/openai.js +17 -12
- package/dist/brain/provider-dialect.d.ts +39 -3
- package/dist/brain/provider-dialect.js +28 -0
- package/dist/brain/reasoning.d.ts +1 -1
- package/dist/brain/request-params.d.ts +55 -5
- package/dist/brain/request-params.js +35 -3
- package/dist/brain/retry.d.ts +1 -1
- package/dist/brain/route-adjudicator.d.ts +15 -0
- package/dist/brain/route-adjudicator.js +15 -0
- package/dist/brain/stream-engine.js +6 -5
- package/dist/brain/stream-shared.d.ts +1 -1
- package/dist/core/advisor-verdict.d.ts +120 -0
- package/dist/core/advisor-verdict.js +92 -0
- package/dist/core/agent-definition.d.ts +7 -8
- package/dist/core/allow-entry.d.ts +49 -23
- package/dist/core/allow-entry.js +57 -32
- package/dist/core/allow-rule-shadow.d.ts +7 -0
- package/dist/core/approval-object.d.ts +2 -1
- package/dist/core/approval-object.js +6 -6
- package/dist/core/ask-origin.d.ts +63 -11
- package/dist/core/ask-origin.js +27 -5
- package/dist/core/ask-question.js +10 -4
- package/dist/core/auto-compaction.d.ts +11 -8
- package/dist/core/auto-compaction.js +4 -2
- package/dist/core/auto-mode-arming.d.ts +2 -2
- package/dist/core/auto-mode-defaults.d.ts +8 -8
- package/dist/core/auto-mode-prompt-assets.d.ts +3 -3
- package/dist/core/auto-mode-prompt.d.ts +1 -1
- package/dist/core/auto-mode.d.ts +17 -9
- package/dist/core/auto-mode.js +9 -6
- package/dist/core/background-agent-store.d.ts +3 -3
- package/dist/core/canonical-json.d.ts +1 -1
- package/dist/core/canonical-json.js +2 -2
- package/dist/core/checkpoint-requirements.d.ts +6 -3
- package/dist/core/checkpoint-requirements.js +4 -14
- package/dist/core/checkpoint-store.d.ts +80 -51
- package/dist/core/checkpoint-store.js +56 -74
- package/dist/core/child-clamp-seats.d.ts +6 -0
- package/dist/core/child-clamp-seats.js +3 -16
- package/dist/core/compliance.d.ts +2 -2
- package/dist/core/context-edit.d.ts +6 -7
- package/dist/core/cross-boundary-taint.d.ts +9 -3
- package/dist/core/cross-boundary-taint.js +5 -3
- package/dist/core/decision-receipt.js +2 -2
- package/dist/core/effective-path-target.d.ts +1 -1
- package/dist/core/engine-notice.d.ts +19 -5
- package/dist/core/exec-output-tail.d.ts +1 -1
- package/dist/core/file-history-retention.d.ts +1 -1
- package/dist/core/file-history-store.d.ts +59 -9
- package/dist/core/file-history-store.js +35 -17
- package/dist/core/gate-fold.js +3 -2
- package/dist/core/gate-lanes.js +12 -8
- package/dist/core/gate-outcome.d.ts +17 -4
- package/dist/core/gate-outcome.js +30 -0
- package/dist/core/governance-codes.d.ts +13 -3
- package/dist/core/governance-codes.js +10 -0
- package/dist/core/hands-band.d.ts +1 -1
- package/dist/core/hooks.d.ts +4 -4
- package/dist/core/host-target.d.ts +49 -0
- package/dist/core/host-target.js +59 -0
- package/dist/core/image-downsample.d.ts +1 -1
- package/dist/core/lsp-diagnostics.d.ts +4 -4
- package/dist/core/lsp.d.ts +3 -3
- package/dist/core/mailbox-store.d.ts +4 -0
- package/dist/core/mcp-connection-pool.d.ts +18 -2
- package/dist/core/mcp-connection-pool.js +53 -6
- package/dist/core/mcp-failure.d.ts +23 -4
- package/dist/core/mcp-failure.js +26 -11
- package/dist/core/mcp-listing-drift.d.ts +10 -0
- package/dist/core/mcp-listing-drift.js +6 -0
- package/dist/core/mcp-server-link.d.ts +173 -0
- package/dist/core/mcp-server-link.js +127 -0
- package/dist/core/mcp-server-spec.d.ts +4 -2
- package/dist/core/mcp-session-end.d.ts +26 -0
- package/dist/core/mcp-session-end.js +29 -0
- package/dist/core/mcp-startup-request.d.ts +17 -0
- package/dist/core/mcp-startup-request.js +17 -0
- package/dist/core/mcp.d.ts +13 -13
- package/dist/core/mcp.js +187 -162
- package/dist/core/media-byte-cap.d.ts +1 -1
- package/dist/core/memory-engine/engine.d.ts +9 -9
- package/dist/core/memory-engine/provenance-wording.d.ts +1 -1
- package/dist/core/memory-engine/tools.js +4 -1
- package/dist/core/mode-policy.d.ts +1 -1
- package/dist/core/namespaced-rule-name.d.ts +33 -7
- package/dist/core/namespaced-rule-name.js +39 -25
- package/dist/core/output-style.d.ts +1 -1
- package/dist/core/param-rule-reach.d.ts +15 -0
- package/dist/core/param-rule-reach.js +30 -0
- package/dist/core/parent-spec-seat.d.ts +8 -1
- package/dist/core/parent-spec-seat.js +4 -0
- package/dist/core/pause-registry.d.ts +16 -5
- package/dist/core/pause-registry.js +6 -2
- package/dist/core/peer-channel.d.ts +70 -0
- package/dist/core/peer-channel.js +1 -0
- package/dist/core/permission-rule-consent.d.ts +11 -5
- package/dist/core/permission-rule-consent.js +37 -30
- package/dist/core/permission-rule-model.d.ts +233 -64
- package/dist/core/permission-rule-model.js +384 -85
- package/dist/core/permission-rule-provider.d.ts +2 -1
- package/dist/core/permission-rule-store.d.ts +20 -25
- package/dist/core/permission-rule-store.js +1 -4
- package/dist/core/permission-rule-sync.d.ts +11 -2
- package/dist/core/permission-rule-sync.js +8 -1
- package/dist/core/permission-rules.d.ts +49 -11
- package/dist/core/permission-rules.js +123 -89
- package/dist/core/persisted-rule-arms.d.ts +4 -2
- package/dist/core/present-plan-tool.js +3 -1
- package/dist/core/protocol-naming.d.ts +2 -2
- package/dist/core/read-only-shell-table.d.ts +1 -1
- package/dist/core/read-only-shell.d.ts +1 -1
- package/dist/core/roles.d.ts +6 -2
- package/dist/core/roles.js +45 -44
- package/dist/core/rule-offer-read.d.ts +53 -0
- package/dist/core/rule-offer-read.js +146 -0
- package/dist/core/rule-owner.d.ts +46 -0
- package/dist/core/rule-owner.js +28 -0
- package/dist/core/runner/advisor-instructions.d.ts +70 -0
- package/dist/core/runner/advisor-instructions.js +61 -0
- package/dist/core/runner/advisor-tool.d.ts +33 -0
- package/dist/core/runner/advisor-tool.js +112 -0
- package/dist/core/runner/announce-once-ledger.d.ts +4 -26
- package/dist/core/runner/announce-once-ledger.js +14 -46
- package/dist/core/runner/approval-feedback.js +6 -3
- package/dist/core/runner/assemble-result.d.ts +1 -1
- package/dist/core/runner/caller-roster.d.ts +7 -0
- package/dist/core/runner/caller-roster.js +11 -0
- package/dist/core/runner/classifier-ladder.d.ts +27 -5
- package/dist/core/runner/classifier-ladder.js +12 -11
- package/dist/core/runner/compaction-restate.d.ts +10 -6
- package/dist/core/runner/compaction-restate.js +9 -3
- package/dist/core/runner/contracts.d.ts +13 -9
- package/dist/core/runner/conversation-segment.d.ts +28 -0
- package/dist/core/runner/conversation-segment.js +42 -0
- package/dist/core/runner/cross-boundary-lane.d.ts +6 -5
- package/dist/core/runner/cross-boundary-lane.js +26 -15
- package/dist/core/runner/decide-continuation.d.ts +7 -4
- package/dist/core/runner/decide-continuation.js +2 -2
- package/dist/core/runner/denial-limit-arms.d.ts +2 -2
- package/dist/core/runner/derived-route-fallback.d.ts +24 -24
- package/dist/core/runner/derived-route-fallback.js +9 -7
- package/dist/core/runner/gate-exit.d.ts +6 -0
- package/dist/core/runner/gate-exit.js +7 -2
- package/dist/core/runner/initial-run-state.js +1 -1
- package/dist/core/runner/permission-rule-lanes.d.ts +2 -2
- package/dist/core/runner/permission-rule-lanes.js +14 -7
- package/dist/core/runner/person-path-rows.js +1 -1
- package/dist/core/runner/prepare-advisor.d.ts +63 -0
- package/dist/core/runner/prepare-advisor.js +77 -0
- package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
- package/dist/core/runner/prepare-config-doors.d.ts +6 -4
- package/dist/core/runner/prepare-config-doors.js +18 -12
- package/dist/core/runner/prepare-delegation-surface.d.ts +2 -2
- package/dist/core/runner/prepare-delegation-surface.js +1 -1
- package/dist/core/runner/prepare-file-history.js +39 -39
- package/dist/core/runner/prepare-gate-stations.d.ts +1 -4
- package/dist/core/runner/prepare-gate-stations.js +2 -7
- package/dist/core/runner/prepare-inherited-gate.d.ts +5 -4
- package/dist/core/runner/prepare-inherited-gate.js +3 -3
- package/dist/core/runner/prepare-park-ask.js +7 -7
- package/dist/core/runner/prepare-policy-chain.d.ts +1 -1
- package/dist/core/runner/prepare-policy-chain.js +4 -10
- package/dist/core/runner/prepare-project-context.d.ts +5 -2
- package/dist/core/runner/prepare-project-context.js +6 -3
- package/dist/core/runner/prepare-prompt-inputs.js +1 -1
- package/dist/core/runner/prepare-protocol-tools.d.ts +2 -2
- package/dist/core/runner/prepare-protocol-tools.js +3 -2
- package/dist/core/runner/prepare-safety-scan.d.ts +9 -12
- package/dist/core/runner/prepare-safety-scan.js +8 -6
- package/dist/core/runner/prepare-task.js +15 -18
- package/dist/core/runner/prepare-tool-disclosure-mount.js +6 -4
- package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -3
- package/dist/core/runner/prepare-wiring-manifest.js +2 -2
- package/dist/core/runner/resume-policy-outcome.js +1 -1
- package/dist/core/runner/retired-runner-deps.js +1 -1
- package/dist/core/runner/run-attachment-seats.js +0 -1
- package/dist/core/runner/run-compaction-machinery.d.ts +1 -1
- package/dist/core/runner/run-compaction-machinery.js +2 -12
- package/dist/core/runner/run-git-lane.d.ts +1 -0
- package/dist/core/runner/run-harness-handlers.js +2 -3
- package/dist/core/runner/run-leg.js +13 -0
- package/dist/core/runner/run-settle-and-teardown.js +1 -1
- package/dist/core/runner/run-telemetry-and-budget-seats.js +1 -1
- package/dist/core/runner/run-turn-boundary.d.ts +1 -0
- package/dist/core/runner/run-turn-boundary.js +14 -12
- package/dist/core/runner/session-rule-policy.d.ts +22 -21
- package/dist/core/runner/session-rule-policy.js +13 -28
- package/dist/core/runner/side-call-account.d.ts +32 -8
- package/dist/core/runner/side-call-account.js +23 -1
- package/dist/core/runner/strict-output-schema.d.ts +1 -1
- package/dist/core/runner/sub-agent-deny-lists.js +4 -3
- package/dist/core/runner/synthetic-tools.d.ts +10 -13
- package/dist/core/runner/synthetic-tools.js +4 -2
- package/dist/core/runner/tool-disclosure.js +2 -1
- package/dist/core/runner/tool-face-overlay.d.ts +2 -1
- package/dist/core/runner/tool-face-overlay.js +17 -1
- package/dist/core/runner/tool-progress-lane.d.ts +2 -2
- package/dist/core/runner/tool-turn-repair-seat.d.ts +3 -2
- package/dist/core/runner/turn-attachments.d.ts +60 -67
- package/dist/core/runner-deps.d.ts +37 -37
- package/dist/core/runtime-caps.d.ts +4 -4
- package/dist/core/safety-merge-corpus.js +17 -1
- package/dist/core/same-plain-value.d.ts +40 -0
- package/dist/core/same-plain-value.js +49 -0
- package/dist/core/scheduler.d.ts +1 -1
- package/dist/core/sensitive-path-policy.d.ts +1 -1
- package/dist/core/sensitive-path-policy.js +1 -1
- package/dist/core/session-policy-store.d.ts +77 -22
- package/dist/core/session-policy-store.js +56 -14
- package/dist/core/session-reconcile.d.ts +2 -2
- package/dist/core/session-store.d.ts +80 -30
- package/dist/core/session-store.js +118 -76
- package/dist/core/session.d.ts +24 -46
- package/dist/core/shared-memory/tools.js +3 -1
- package/dist/core/shared-memory/types.d.ts +1 -1
- package/dist/core/side-query.d.ts +10 -0
- package/dist/core/side-query.js +5 -0
- package/dist/core/store-contracts/checkpoint-store-contract.js +29 -2
- package/dist/core/store-contracts/file-history-store-contract.js +43 -3
- package/dist/core/store-contracts/session-policy-store-contract.d.ts +7 -0
- package/dist/core/store-contracts/session-policy-store-contract.js +130 -0
- package/dist/core/store-contracts/session-repo-contract.js +125 -0
- package/dist/core/store-contracts/session-store-contract.d.ts +4 -7
- package/dist/core/store-contracts/session-store-contract.js +215 -41
- package/dist/core/store-contracts/workflow-journal-store-contract.js +26 -1
- package/dist/core/surrogate-safe-slice.d.ts +3 -3
- package/dist/core/task-event.d.ts +10 -4
- package/dist/core/task-notification.d.ts +3 -3
- package/dist/core/task-registry-agent.d.ts +4 -4
- package/dist/core/task-registry-shared.d.ts +4 -4
- package/dist/core/task-registry-shared.js +1 -0
- package/dist/core/task-registry.d.ts +4 -4
- package/dist/core/task-registry.js +3 -1
- package/dist/core/task-result.d.ts +3 -3
- package/dist/core/task-spec.d.ts +52 -52
- package/dist/core/task-stream.d.ts +6 -6
- package/dist/core/task-tool-shape.d.ts +4 -4
- package/dist/core/tighten-task-spec.d.ts +1 -1
- package/dist/core/tool-catalog-entries.d.ts +19 -2
- package/dist/core/tool-catalog-entries.js +57 -42
- package/dist/core/tool-conformance.js +1 -0
- package/dist/core/tool-errors.d.ts +2 -2
- package/dist/core/tool-face-reader.js +5 -3
- package/dist/core/tool-face.d.ts +21 -2
- package/dist/core/tool-face.js +1 -1
- package/dist/core/tool-model-gate.d.ts +3 -3
- package/dist/core/tool-name-aliases.d.ts +29 -8
- package/dist/core/tool-name-aliases.js +27 -3
- package/dist/core/tool-name-readings.d.ts +5 -8
- package/dist/core/tool-name-readings.js +1 -2
- package/dist/core/tool-policy.d.ts +24 -5
- package/dist/core/tool-policy.js +34 -10
- package/dist/core/tool-registry.d.ts +14 -7
- package/dist/core/tool-registry.js +17 -7
- package/dist/core/tool-result-store.js +2 -1
- package/dist/core/tool-roster.d.ts +47 -18
- package/dist/core/tool-roster.js +53 -32
- package/dist/core/tool-spec-members.js +1 -1
- package/dist/core/tool-spec.d.ts +35 -21
- package/dist/core/tools.js +3 -2
- package/dist/core/trace.d.ts +4 -0
- package/dist/core/untrusted-egress.d.ts +1 -1
- package/dist/core/untrusted-text.d.ts +1 -1
- package/dist/core/warm-resume.d.ts +1 -1
- package/dist/core/wiring-manifest.d.ts +49 -0
- package/dist/core/wiring-manifest.js +13 -5
- package/dist/core/workflow-journal-store.d.ts +62 -0
- package/dist/core/workflow-journal-store.js +77 -1
- package/dist/core/workflow-run-store.d.ts +6 -0
- package/dist/core/workflow-run-store.js +2 -0
- package/dist/engine/compaction/compaction.d.ts +9 -9
- package/dist/engine/execution-env/node-execution-env.d.ts +19 -5
- package/dist/engine/execution-env/node-execution-env.js +43 -22
- package/dist/engine/harness/agent-harness.d.ts +14 -8
- package/dist/engine/harness/agent-harness.js +33 -26
- package/dist/engine/harness/types.d.ts +29 -7
- package/dist/engine/harness/types.js +12 -1
- package/dist/engine/llm/types.d.ts +9 -9
- package/dist/engine/llm/validation.d.ts +4 -1
- package/dist/engine/llm/validation.js +13 -1
- package/dist/engine/loop/agent-loop.d.ts +1 -1
- package/dist/engine/loop/agent-loop.js +10 -8
- package/dist/engine/loop/types.d.ts +15 -13
- package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
- package/dist/engine/session/memory-repo.d.ts +10 -11
- package/dist/engine/session/memory-repo.js +13 -8
- package/dist/engine/session/parent-chain-guard.d.ts +3 -2
- package/dist/engine/session/parent-chain-guard.js +1 -1
- package/dist/engine/session/repo-utils.d.ts +31 -3
- package/dist/engine/session/repo-utils.js +42 -5
- package/dist/index.d.ts +27 -15
- package/dist/index.js +21 -11
- package/dist/internal/harness-types.d.ts +1 -1
- package/dist/internal/harness.d.ts +3 -3
- package/dist/internal/harness.js +2 -2
- package/dist/internal/llm.d.ts +1 -1
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/goal.js +2 -2
- package/dist/orchestration/run-workflow-tool.d.ts +2 -2
- package/dist/orchestration/run-workflow-tool.js +5 -3
- package/dist/orchestration/workflow-size-guideline.d.ts +4 -4
- package/dist/orchestration/workflow-types.d.ts +18 -0
- package/dist/orchestration/workflow-types.js +6 -0
- package/dist/orchestration/workflow.d.ts +2 -13
- package/dist/orchestration/workflow.js +21 -31
- package/dist/prompt-assembly/event-registry.js +1 -0
- package/dist/prompt-assembly/tool-catalog.d.ts +3 -0
- package/dist/prompt-assembly/tool-catalog.js +3 -0
- package/dist/prompts/default.d.ts +14 -14
- package/dist/scenarios/full-body.d.ts +4 -4
- package/dist/stores/file/adoption/adopt.d.ts +4 -3
- package/dist/stores/file/adoption/adopt.js +24 -31
- package/dist/stores/file/adoption/marker.d.ts +6 -13
- package/dist/stores/file/adoption/marker.js +6 -15
- package/dist/stores/file/checkpoint-store.d.ts +3 -0
- package/dist/stores/file/checkpoint-store.js +9 -3
- package/dist/stores/file/file-history-store.d.ts +20 -19
- package/dist/stores/file/file-history-store.js +152 -135
- package/dist/stores/file/fs-atomic.d.ts +15 -0
- package/dist/stores/file/fs-atomic.js +89 -14
- package/dist/stores/file/index.d.ts +1 -1
- package/dist/stores/file/mailbox-store.d.ts +3 -0
- package/dist/stores/file/mailbox-store.js +3 -1
- package/dist/stores/file/permission-rule-adopt.d.ts +1 -1
- package/dist/stores/file/permission-rule-adopt.js +15 -16
- package/dist/stores/file/permission-rule-store.d.ts +18 -2
- package/dist/stores/file/permission-rule-store.js +21 -14
- package/dist/stores/file/session-policy-store.d.ts +3 -3
- package/dist/stores/file/session-store.d.ts +26 -11
- package/dist/stores/file/session-store.js +77 -40
- package/dist/stores/file/workflow-journal-store.d.ts +10 -4
- package/dist/stores/file/workflow-journal-store.js +28 -13
- package/dist/tools/artifact/artifact-text.d.ts +1 -1
- package/dist/tools/artifact/artifact-tool.js +2 -1
- package/dist/tools/fs/bash-readonly-classifier.d.ts +3 -3
- package/dist/tools/fs/fs-bash.d.ts +2 -2
- package/dist/tools/fs/fs-bash.js +3 -1
- package/dist/tools/fs/fs-shared.d.ts +8 -8
- package/dist/tools/fs/gh-rate-limit.d.ts +1 -1
- package/dist/tools/fs/notebook.d.ts +2 -2
- package/dist/tools/fs/read-deny.d.ts +29 -7
- package/dist/tools/fs/read-deny.js +63 -22
- package/dist/tools/fs/removal-targets.d.ts +1 -1
- package/dist/tools/fs/safety.d.ts +9 -9
- package/dist/tools/fs/search.d.ts +6 -6
- package/dist/tools/fs/shell-read-check.js +6 -1
- package/dist/tools/fs/shell-read-judge.d.ts +4 -0
- package/dist/tools/fs/shell-read-judge.js +5 -2
- package/dist/tools/loop-tick.d.ts +2 -2
- package/dist/tools/scheduler-tools.js +5 -1
- package/dist/tools/task-list.d.ts +7 -7
- package/dist/tools/task-list.js +5 -1
- package/dist/tools/todo.js +2 -1
- package/dist/tools/web.d.ts +1 -1
- package/dist/tools/web.js +40 -37
- package/dist/tools/worktree.d.ts +3 -3
- package/dist/tools/worktree.js +3 -1
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +5756 -5638
- package/wire-changes/core@7.55.0.json +3318 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +0 -39
- package/dist/core/store-contracts/session-store-incarnation-contract.js +0 -95
|
@@ -16,3 +16,10 @@ export interface AllowRuleShadow {
|
|
|
16
16
|
readonly entries: readonly string[];
|
|
17
17
|
readonly omitted?: number;
|
|
18
18
|
}
|
|
19
|
+
/** The allow-layer member that CLEARED a call's ask (`tool_end.gate.disposition.clearedBy`): the shadow record's shape — the member
|
|
20
|
+
* and the entries it stood on, sanitized and capped by the same mint — plus, for a LIST member (`request`, `deployment`),
|
|
21
|
+
* `positions`: the index of every element of the list the run received that is one of those entries (a string listed twice has
|
|
22
|
+
* both indices), so a host reads which line of its own declaration spoke even where the shown text is capped. */
|
|
23
|
+
export interface AllowRuleClearance extends AllowRuleShadow {
|
|
24
|
+
readonly positions?: readonly number[];
|
|
25
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PendingAction } from "./checkpoint-store.js";
|
|
2
2
|
import type { CallTargetReading } from "./effective-path-target.js";
|
|
3
3
|
import { type SkillGrantSource } from "./skill-grant.js";
|
|
4
|
-
import type { ToolCallPathTarget, ToolFamily } from "./tool-face.js";
|
|
4
|
+
import type { ToolCallPathTarget, ToolFamily, ToolHostTarget } from "./tool-face.js";
|
|
5
5
|
import { type ToolRosterEntry } from "./tool-roster.js";
|
|
6
6
|
type ParkedApproval = Extract<PendingAction, {
|
|
7
7
|
kind: "tool_approval";
|
|
@@ -24,6 +24,7 @@ export interface ApprovalTool {
|
|
|
24
24
|
readonly implementationRevision?: string;
|
|
25
25
|
readonly family?: ToolFamily;
|
|
26
26
|
readonly pathTarget?: ToolCallPathTarget;
|
|
27
|
+
readonly hostTarget?: ToolHostTarget;
|
|
27
28
|
}
|
|
28
29
|
export interface ApprovalObject {
|
|
29
30
|
/** Absent on a row minted before the identity members (all four absent): such a row binds the tool's name alone. */
|
|
@@ -5,10 +5,10 @@ import { toolIdentityOf } from "./tool-roster.js";
|
|
|
5
5
|
import { inlineUntrusted } from "./untrusted-text.js";
|
|
6
6
|
export const APPROVAL_TARGET_ROLES = Object.freeze(["protective", "declared"]);
|
|
7
7
|
export function approvalObjectOf(row) {
|
|
8
|
-
const { capabilityId, contractId, shapeDigest, implementationRevision, family, pathTarget, targets, boundGrantDigest } = row;
|
|
8
|
+
const { capabilityId, contractId, shapeDigest, implementationRevision, family, pathTarget, hostTarget, targets, boundGrantDigest } = row;
|
|
9
9
|
const carried = [capabilityId, contractId, shapeDigest, implementationRevision].some((m) => m !== undefined);
|
|
10
10
|
return {
|
|
11
|
-
...(carried ? { tool: { capabilityId, contractId, shapeDigest, implementationRevision, family, pathTarget } } : {}),
|
|
11
|
+
...(carried ? { tool: { capabilityId, contractId, shapeDigest, implementationRevision, family, pathTarget, hostTarget } } : {}),
|
|
12
12
|
...(targets !== undefined ? { targets } : {}),
|
|
13
13
|
...(boundGrantDigest !== undefined ? { grants: boundGrantDigest } : {}),
|
|
14
14
|
};
|
|
@@ -30,9 +30,9 @@ export const APPROVAL_STATION_MEMBERS = Object.freeze({
|
|
|
30
30
|
const IDENTITY_MEMBERS = Object.freeze(["capabilityId", "contractId", "shapeDigest", "implementationRevision"]);
|
|
31
31
|
const shown = (s) => `"${inlineUntrusted(s, 240)}"`;
|
|
32
32
|
const vetoed = (name, why) => `The approved tool call "${name}" was not executed: ${why}, so the approval does not cover it (resume.target_moved). This approval is spent — the call has to be re-issued: its new card shows what it would act on now.`;
|
|
33
|
-
function faceKey(family, pt) {
|
|
33
|
+
function faceKey(family, pt, ht) {
|
|
34
34
|
const slot = pt === undefined ? null : { param: pt.param, access: pt.access, aliases: [...(pt.aliases ?? [])], base: pt.base ?? "cwd", absent: pt.absent ?? "none", patternParam: pt.patternParam ?? null, skillScopeEligible: pt.skillScopeEligible === true };
|
|
35
|
-
return canonicalize({ family: family ?? null, pathTarget: slot });
|
|
35
|
+
return canonicalize({ family: family ?? null, pathTarget: slot, hostTarget: ht === undefined ? null : { param: ht.param } });
|
|
36
36
|
}
|
|
37
37
|
function judgeTool(row, live) {
|
|
38
38
|
const entry = live.tool;
|
|
@@ -47,9 +47,9 @@ function judgeTool(row, live) {
|
|
|
47
47
|
const named = differ.map((k) => (bound[k] === undefined ? `${k} (missing on the row)` : k)).join(", ");
|
|
48
48
|
return { member: "tool", disposition: "reopen", code: "resume.tool_contract_mismatch", message: `the approved tool "${row.toolName}" on this leg is not the tool the approval was minted against (${named} differ) — refusing to execute a replacement wearing the name; the checkpoint is reopened for a retry with the original tool present` };
|
|
49
49
|
}
|
|
50
|
-
if (faceKey(bound.family, bound.pathTarget) === faceKey(entry.family, entry.pathTarget))
|
|
50
|
+
if (faceKey(bound.family, bound.pathTarget, bound.hostTarget) === faceKey(entry.family, entry.pathTarget, entry.hostTarget))
|
|
51
51
|
return undefined;
|
|
52
|
-
return { member: "tool", disposition: "veto", code: "resume.target_moved", message: vetoed(row.toolName, "the tool's face (its display family or the path target it declares) changed after the approval") };
|
|
52
|
+
return { member: "tool", disposition: "veto", code: "resume.target_moved", message: vetoed(row.toolName, "the tool's face (its display family, or the path target or URL slot it declares) changed after the approval") };
|
|
53
53
|
}
|
|
54
54
|
function judgeTargets(row, live) {
|
|
55
55
|
const bound = row.targets;
|
|
@@ -251,6 +251,18 @@ export declare function askMandateMember(ask: RuleClearanceFacts | undefined): {
|
|
|
251
251
|
mandate?: PersistedRuleMandate;
|
|
252
252
|
authoredBy?: "deployment";
|
|
253
253
|
};
|
|
254
|
+
/**
|
|
255
|
+
* A MANDATE merged onto an ask another layer raised — the one writer of both merge arms (the read station's, the reversibility
|
|
256
|
+
* probe's; `gate-fold.ts`). The mandate is the fact that a standing allow rule may not clear the ask, and its account is the only
|
|
257
|
+
* sentence that can say why (the allow layer's disclosure words a `probe_mandate` with it, on the card and in the parked row): the
|
|
258
|
+
* two travel together. The FIRST layer to mandate an ask brings its account, or none: a `probeReason` the ask arrived with can only
|
|
259
|
+
* be its own author's prose, and is replaced by the account — or removed where the mandating layer gave none, so it is never read as
|
|
260
|
+
* the reason the mandate stands; an ask already mandated keeps the first layer's. The ask's action, message, reason and every other
|
|
261
|
+
* disclosure are untouched.
|
|
262
|
+
*/
|
|
263
|
+
export declare function withProbeMandate<D extends Extract<PermissionResult, {
|
|
264
|
+
action: "ask";
|
|
265
|
+
}>>(decision: D, account: string | undefined): D;
|
|
254
266
|
/** The clearance facts of an ask the engine did not construct (a policy's verdict), each member read ONCE into
|
|
255
267
|
* an engine-owned value — for a station that keeps the answer past its own side effects, where the verdict's
|
|
256
268
|
* accessors must not run again. The members a verdict may carry that narrow what may clear it. */
|
|
@@ -300,8 +312,10 @@ export type RealApprovalTableCoversEveryOrigin = AssertAllKeysHandled<Exclude<As
|
|
|
300
312
|
*
|
|
301
313
|
* - `operator_always` — the operator's `always` floor: per-call confirmation for shell commands.
|
|
302
314
|
* - `tool_marks` — the tool's own egress / irreversibility / interaction declaration.
|
|
303
|
-
* - `probe_mandate` — this call's reversibility probe declared the demotion STRUCTURAL.
|
|
304
|
-
*
|
|
315
|
+
* - `probe_mandate` — this call's reversibility probe declared the demotion STRUCTURAL. For the engine's own shell station it
|
|
316
|
+
* is a FINDING about this call — a path outside the allowed directories (read or written) or a command whose reads it could
|
|
317
|
+
* not establish — and the finding's account (the ask's `probeReason`) is the word's whole disclosure ({@link FINDING_ACCOUNT}).
|
|
318
|
+
* - `probe_unanswered` — the probe was consulted and did not answer: whether the call is reversible is UNKNOWN.
|
|
305
319
|
* - `write_protection` — the table covers this write's target. A write onto load-executed configuration
|
|
306
320
|
* re-authorizes the agent, so the question is a property of the TARGET, not of anyone's hesitation.
|
|
307
321
|
* - `target_unresolved` — the reading of a written target could not say where it leads on disk:
|
|
@@ -314,11 +328,20 @@ export declare const PERSISTED_RULE_MANDATES: readonly ["operator_always", "tool
|
|
|
314
328
|
export type PersistedRuleMandate = (typeof PERSISTED_RULE_MANDATES)[number];
|
|
315
329
|
/** Membership test for {@link PersistedRuleMandate} — the screen a row reader applies to a stored word. */
|
|
316
330
|
export declare function isPersistedRuleMandate(v: unknown): v is PersistedRuleMandate;
|
|
331
|
+
/** The row of a word whose reason is a FINDING about this very call (what the read station found — a path outside the allowed
|
|
332
|
+
* directories, read or written, or a command whose reads it could not establish): no sentence of the table can say which, so
|
|
333
|
+
* the reason is the finding's own account — the sentence the station minted for the card, which the ask carries as
|
|
334
|
+
* `probeReason` ({@link mandateDisclosureOf} reads it there). A row, not an absence: the word is disclosed, by the ask. */
|
|
335
|
+
export declare const FINDING_ACCOUNT: Readonly<{
|
|
336
|
+
readonly reasonIs: "the account of the finding, carried on the ask as probeReason";
|
|
337
|
+
}>;
|
|
317
338
|
/** WHY a matching persisted allow rule did not clear the ask, in the sentence a PERSON reads — one row per
|
|
318
339
|
* word (the ladder this replaces ended in a catch-all arm). Display prose; nothing reads it back to decide. */
|
|
319
|
-
declare const MANDATE_DISCLOSURE: {
|
|
320
|
-
readonly probe_mandate:
|
|
321
|
-
|
|
340
|
+
export declare const MANDATE_DISCLOSURE: {
|
|
341
|
+
readonly probe_mandate: Readonly<{
|
|
342
|
+
readonly reasonIs: "the account of the finding, carried on the ask as probeReason";
|
|
343
|
+
}>;
|
|
344
|
+
readonly probe_unanswered: "the reversibility check did not answer for this call (it timed out or failed), so whether the call is reversible is unknown — it is cleared by confirming this call, never by a standing allow rule";
|
|
322
345
|
readonly operator_always: "this deployment mandates per-call confirmation for shell commands (shellGate: always)";
|
|
323
346
|
readonly tool_marks: "this tool carries egress/irreversibility/interaction marks (a mandated confirmation a rule cannot clear)";
|
|
324
347
|
readonly write_protection: "this write's target is on the deployment's write-protection table (the agent's own configuration is guarded one look per write) — it is cleared by confirming this call, never by a standing allow rule";
|
|
@@ -327,9 +350,18 @@ declare const MANDATE_DISCLOSURE: {
|
|
|
327
350
|
};
|
|
328
351
|
/** The fence over the disclosure table: `never` while every word has a row. */
|
|
329
352
|
export type DisclosureTableCoversEveryMandate = AssertAllKeysHandled<Exclude<PersistedRuleMandate, keyof typeof MANDATE_DISCLOSURE>>;
|
|
330
|
-
/** The
|
|
331
|
-
*
|
|
332
|
-
export declare
|
|
353
|
+
/** The sentence for the lane's OTHER refusal — no mandate: a standing "ask me each time" rule matched, which outranks the
|
|
354
|
+
* remembered yes on its own. */
|
|
355
|
+
export declare const ASK_RULE_DISCLOSURE = "an explicit ask rule matched this call (a person's or the deployment's ask-me-each-time outranks a standing allow rule)";
|
|
356
|
+
/**
|
|
357
|
+
* The disclosed reason for one word. `undefined` — no mandate — is the lane's OTHER refusal ({@link ASK_RULE_DISCLOSURE}).
|
|
358
|
+
* A word whose row is {@link FINDING_ACCOUNT} is disclosed by the ask's own account of its finding (`account`, the
|
|
359
|
+
* `probeReason` the ask carries) and by nothing else: with no account there is no sentence (`undefined`) — a word whose reason is
|
|
360
|
+
* a finding is never worded from a general statement, which would be true of one finding and false of the next. Every
|
|
361
|
+
* mandate the engine's own read station raises carries its account; an ask that arrives without one (a deployment probe that
|
|
362
|
+
* supplied no `reason`, a station the host mounted) is a mandate stated without a reason, and the card does not invent one.
|
|
363
|
+
*/
|
|
364
|
+
export declare function mandateDisclosureOf(mandate: PersistedRuleMandate | undefined, account?: string): string | undefined;
|
|
333
365
|
/**
|
|
334
366
|
* The mandate provenance of one call, judged from the SAME mark inputs the gate is driven with —
|
|
335
367
|
* the WORD a mandated ask discloses for its marks (the class derivation reads the same marks as classes,
|
|
@@ -809,9 +841,25 @@ export declare function classifyAsk(d: Extract<PermissionResult, {
|
|
|
809
841
|
action: "ask";
|
|
810
842
|
}>, facts: AskClassFacts): AskClassification;
|
|
811
843
|
/** The refusal the model reads when an ask reaches a run with no approver: the reference implementation's sentence
|
|
812
|
-
*
|
|
844
|
+
* the call did NOT run because this session has no approval surface — with the run's own fact beside it
|
|
813
845
|
* and the ask's prompt as what was requested. The gate appends the caller-side remedy. */
|
|
814
846
|
export declare function headlessDenialMessage(toolName: string, askMessage: string): string;
|
|
847
|
+
/**
|
|
848
|
+
* The refusal the model reads when the `dontAsk` permission mode refuses an ask (`deniedBy: "mode"`): the reference implementation's
|
|
849
|
+
* head (whose permission, which mode — with the ask's class beside it) and its guidance ({@link REFUSED_CAPABILITY_GUIDANCE}), then
|
|
850
|
+
* the way out, the ONE remedy function's `dontAsk` arm ({@link headlessApprovalRemedy}) — the same sentence a headless refusal's
|
|
851
|
+
* remedy is written by, so a mode refusal and a headless one say the way out in one voice. `ruleShape` is the shape of the allow
|
|
852
|
+
* rule that would speak for the call (`ruleShapeOf` under `allow`, the rule model's reading of the call's grammar). The sentence
|
|
853
|
+
* names where allow rules live in a person's words (a settings file, the request's or the deployment's allow list), never a seat
|
|
854
|
+
* of the library: a host reads the same answer off the denied disposition — `deniedBy: "mode"`, `mode`, and the folded
|
|
855
|
+
* `classes`, whose row ({@link foldArbitrationRow}) says `ruleMayClear` — and offers its own seat.
|
|
856
|
+
*/
|
|
857
|
+
export declare function dontAskRefusalMessage(input: {
|
|
858
|
+
readonly toolName: string;
|
|
859
|
+
readonly classification: AskClassification;
|
|
860
|
+
readonly coveredWrite: boolean;
|
|
861
|
+
readonly ruleShape: string;
|
|
862
|
+
}): string;
|
|
815
863
|
/** The state of the approver seat a remedy is written for: `absent` — no approver is wired for the leg; `unavailable` — one is
|
|
816
864
|
* wired and answered that nobody is reachable for this ask; `declared_none` — the run declared that nobody on it can be
|
|
817
865
|
* asked (`approvalReach: "none"`), whatever is wired. Absent in the input reads as `absent` (the posture the function was
|
|
@@ -832,6 +880,10 @@ export type HeadlessApproverSeat = "absent" | "unavailable" | "declared_none";
|
|
|
832
880
|
* wire one; one wired that answered `unavailable` for this ask ⇒ make a person reachable through it (a wired approver is
|
|
833
881
|
* never told to be wired); the run declared nobody can be asked ⇒ run it where a person can be, or park it. The refusal's tool text and the `delegation.ask_unresolvable` notice both carry this sentence —
|
|
834
882
|
* they call this function, neither spells it.
|
|
883
|
+
* Under `dontAsk` (the mode answers no ask: {@link dontAskRefusalMessage} carries this arm) the one question is whether an allow
|
|
884
|
+
* rule may clear the ask — the folded row's `ruleMayClear`, the allow layer's own reading: yes ⇒ add an allow rule covering the
|
|
885
|
+
* call, in the tool's rule shape (`ruleShape`, the caller's reading of the call's grammar — never a rule minted for the call), or
|
|
886
|
+
* run under a mode with an approver; no ⇒ only a person can answer it.
|
|
835
887
|
*/
|
|
836
888
|
export declare function headlessApprovalRemedy(input: {
|
|
837
889
|
readonly mode: PermissionMode | undefined;
|
|
@@ -841,8 +893,9 @@ export declare function headlessApprovalRemedy(input: {
|
|
|
841
893
|
readonly program: "cp" | "mv";
|
|
842
894
|
};
|
|
843
895
|
readonly approverSeat?: HeadlessApproverSeat;
|
|
896
|
+
readonly ruleShape?: string;
|
|
844
897
|
}): string;
|
|
845
|
-
/** The reference implementation's sentence
|
|
898
|
+
/** The reference implementation's sentence for a `cp` / `mv` the mode will not answer because it carries option
|
|
846
899
|
* words — the approval card's message under `acceptEdits` and the head of the headless remedy. */
|
|
847
900
|
export declare function fileCommandOptionsSentence(program: "cp" | "mv"): string;
|
|
848
901
|
/** What the mode arbitration decided for one surviving ask. `ask` hands it on unchanged (park / approver); `accepted` is
|
|
@@ -890,4 +943,3 @@ export declare function arbitrateByMode(mode: PermissionMode, c: AskClassificati
|
|
|
890
943
|
}, call?: {
|
|
891
944
|
readonly fileCommand?: boolean;
|
|
892
945
|
}): Arbitration;
|
|
893
|
-
export {};
|
package/dist/core/ask-origin.js
CHANGED
|
@@ -57,6 +57,12 @@ export function askMandateMember(ask) {
|
|
|
57
57
|
const authored = ask?.authoredBy === "deployment" ? { authoredBy: "deployment" } : {};
|
|
58
58
|
return mandated ? { mandated: true, ...(mandate !== undefined ? { mandate } : {}), ...authored } : authored;
|
|
59
59
|
}
|
|
60
|
+
export function withProbeMandate(decision, account) {
|
|
61
|
+
if (decision.probeMandated === true)
|
|
62
|
+
return decision;
|
|
63
|
+
const { probeReason: _arrivedWith, ...rest } = decision;
|
|
64
|
+
return { ...rest, probeMandated: true, ...(account !== undefined ? { probeReason: account } : {}) };
|
|
65
|
+
}
|
|
60
66
|
export function ownedClearanceFacts(d) {
|
|
61
67
|
const { mandated, requiresRealApproval, decisionReason, matchedAskRule, probeMandated, crossBoundaryMandated, authoredBy, foldedAskClasses } = d;
|
|
62
68
|
return {
|
|
@@ -112,17 +118,22 @@ const PERSISTED_RULE_MANDATE_SET = new Set(PERSISTED_RULE_MANDATES);
|
|
|
112
118
|
export function isPersistedRuleMandate(v) {
|
|
113
119
|
return PERSISTED_RULE_MANDATE_SET.has(v);
|
|
114
120
|
}
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
121
|
+
export const FINDING_ACCOUNT = Object.freeze({ reasonIs: "the account of the finding, carried on the ask as probeReason" });
|
|
122
|
+
export const MANDATE_DISCLOSURE = {
|
|
123
|
+
probe_mandate: FINDING_ACCOUNT,
|
|
124
|
+
probe_unanswered: "the reversibility check did not answer for this call (it timed out or failed), so whether the call is reversible is unknown — it is cleared by confirming this call, never by a standing allow rule",
|
|
118
125
|
operator_always: "this deployment mandates per-call confirmation for shell commands (shellGate: always)",
|
|
119
126
|
tool_marks: "this tool carries egress/irreversibility/interaction marks (a mandated confirmation a rule cannot clear)",
|
|
120
127
|
write_protection: "this write's target is on the deployment's write-protection table (the agent's own configuration is guarded one look per write) — it is cleared by confirming this call, never by a standing allow rule",
|
|
121
128
|
target_unresolved: "where this write leads on disk could not be determined (a link on the way could not be examined, or the environment could not resolve the target), so whether it lands on a guarded path is unknown — it is cleared by confirming this call: no standing rule and no automatic decider answers for it, though a wired approver seat can",
|
|
122
129
|
cross_boundary_taint: "this run executes on a device outside the deployment's trust boundary and the deployment is multi-tenant, so an org-side write — or, after an off-target read, a call bound for the device — is confirmed by the deployment's approver for this call: no standing allow rule and no automatic lane answers for it, and an allow the configuration gives (a blanket seat or a policy's answer) is refused",
|
|
123
130
|
};
|
|
124
|
-
export
|
|
125
|
-
|
|
131
|
+
export const ASK_RULE_DISCLOSURE = "an explicit ask rule matched this call (a person's or the deployment's ask-me-each-time outranks a standing allow rule)";
|
|
132
|
+
export function mandateDisclosureOf(mandate, account) {
|
|
133
|
+
if (mandate === undefined)
|
|
134
|
+
return ASK_RULE_DISCLOSURE;
|
|
135
|
+
const row = MANDATE_DISCLOSURE[mandate];
|
|
136
|
+
return typeof row === "string" ? row : account;
|
|
126
137
|
}
|
|
127
138
|
export function persistedRuleMandateOf(marks) {
|
|
128
139
|
if (marks.targetUnresolved === true)
|
|
@@ -366,7 +377,18 @@ export function classifyAsk(d, facts) {
|
|
|
366
377
|
export function headlessDenialMessage(toolName, askMessage) {
|
|
367
378
|
return `Permission for this tool use was denied: it requires interactive approval, and permission prompts are not available in this session (nobody can be asked to approve "${toolName}" in this run — headless auto-deny). The action was NOT performed. Do not claim it succeeded, and do not retry it in this session — report the limitation to the user, or suggest an alternative. What was requested: ${askMessage}`;
|
|
368
379
|
}
|
|
380
|
+
const REFUSED_CAPABILITY_GUIDANCE = "IMPORTANT: you may try to accomplish this with other tools that would naturally be used for it (for example `head` instead of `cat`), but do not work around this denial in malicious ways — for example, do not use your ability to run tests to run non-test actions; only work around it in reasonable ways that keep to the intent behind it. If you believe this capability is essential to complete the user's request, STOP and explain to the user what you were trying to do and why you need this permission, and let the user decide how to proceed.";
|
|
381
|
+
export function dontAskRefusalMessage(input) {
|
|
382
|
+
const remedy = headlessApprovalRemedy({ mode: "dontAsk", classification: input.classification, coveredWrite: input.coveredWrite, ruleShape: input.ruleShape });
|
|
383
|
+
return `Permission to use ${input.toolName} has been denied because this run is in the dontAsk permission mode (this call needed approval: ${input.classification.askClass}). ${REFUSED_CAPABILITY_GUIDANCE} To let a call like this run: ${remedy}.`;
|
|
384
|
+
}
|
|
369
385
|
export function headlessApprovalRemedy(input) {
|
|
386
|
+
if (input.mode === "dontAsk") {
|
|
387
|
+
const c = input.classification;
|
|
388
|
+
return c?.row.ruleMayClear === true
|
|
389
|
+
? `an allow rule covering this call answers it under dontAsk — add one${input.ruleShape !== undefined ? ` in this tool's rule shape (\`${input.ruleShape}\`)` : ""} to the allow rules (a settings file's \`permissions.allow\`, or the request's or the deployment's allow list), or run under a mode with an approver`
|
|
390
|
+
: `no allow rule answers this ask${c !== undefined ? ` (${c.askClass})` : ""} — only a person can: run under a mode with an approver, or change the call`;
|
|
391
|
+
}
|
|
370
392
|
const approver = input.approverSeat === "unavailable"
|
|
371
393
|
? "make a person reachable through the approver that is wired (it answered `unavailable` for this ask)"
|
|
372
394
|
: input.approverSeat === "declared_none"
|
|
@@ -3,7 +3,7 @@ import { uuidv7 } from "../engine/session/uuid.js";
|
|
|
3
3
|
import { boundInputHashOf, capturedJsonOf } from "./canonical-json.js";
|
|
4
4
|
import { defineTool, errorResult } from "./tools.js";
|
|
5
5
|
import { delimitUntrusted, inlineUntrusted } from "./untrusted-text.js";
|
|
6
|
-
import { toolFace } from "./tool-catalog-entries.js";
|
|
6
|
+
import { mountRuleFace, toolFace } from "./tool-catalog-entries.js";
|
|
7
7
|
import { thrownText } from "./thrown-value.js";
|
|
8
8
|
import { heldBy } from "./tool-name-readings.js";
|
|
9
9
|
export const ASK_USER_QUESTION_TOOL_NAME = "AskUserQuestion";
|
|
@@ -112,6 +112,7 @@ export function createAskUserQuestionTool(onQuestion, source, opts) {
|
|
|
112
112
|
return defineTool({
|
|
113
113
|
name: ASK_USER_QUESTION_TOOL_NAME,
|
|
114
114
|
...toolFace("ask-user-question"),
|
|
115
|
+
ruleFace: mountRuleFace("ask-user-question"),
|
|
115
116
|
description: "Ask the user a structured multiple-choice question when you are genuinely stuck or a decision is " +
|
|
116
117
|
"the user's to make (which approach, which of these). Provide 1-4 questions, each with 2-4 options " +
|
|
117
118
|
"(label + description). Use sparingly — not for anything you can determine yourself from the code or " +
|
|
@@ -256,6 +257,11 @@ export function createAskUserQuestionTool(onQuestion, source, opts) {
|
|
|
256
257
|
const untrustedParts = [];
|
|
257
258
|
const answeredHeaders = new Set();
|
|
258
259
|
const inlineSafe = (s) => inlineUntrusted(String(s), 300);
|
|
260
|
+
const echoLabel = (q, label, safe) => {
|
|
261
|
+
const place = q.options.findIndex((o) => o.label === label);
|
|
262
|
+
return place < 0 ? safe(label) : `[${place + 1}] ${safe(label)}`;
|
|
263
|
+
};
|
|
264
|
+
const asIs = (s) => s;
|
|
259
265
|
const capNote = (s) => (s.length > 4000 ? s.slice(0, 4000) + "…" : s);
|
|
260
266
|
let answers;
|
|
261
267
|
try {
|
|
@@ -290,15 +296,15 @@ export function createAskUserQuestionTool(onQuestion, source, opts) {
|
|
|
290
296
|
chosen = chosen.slice(0, 1);
|
|
291
297
|
}
|
|
292
298
|
if (answeredHeaders.has(q.header)) {
|
|
293
|
-
untrustedParts.push(`[${inlineSafe(q.header)}] duplicate answer (already answered): ${[...chosen, ...offList].join(" ")}`);
|
|
299
|
+
untrustedParts.push(`[${inlineSafe(q.header)}] duplicate answer (already answered): ${[...chosen.map((s) => echoLabel(q, s, asIs)), ...offList].join(" ")}`);
|
|
294
300
|
}
|
|
295
301
|
else {
|
|
296
302
|
answeredHeaders.add(q.header);
|
|
297
|
-
trustedLines.push(`- ${inlineSafe(q.header)}: ${chosen.length > 0 ? chosen.map(inlineSafe).join(", ") : "(no listed option selected)"}`);
|
|
303
|
+
trustedLines.push(`- ${inlineSafe(q.header)}: ${chosen.length > 0 ? chosen.map((s) => echoLabel(q, s, inlineSafe)).join(", ") : "(no listed option selected)"}`);
|
|
298
304
|
if (offList.length > 0)
|
|
299
305
|
untrustedParts.push(`[${inlineSafe(q.header)}] off-list input: ${offList.join("\n")}`);
|
|
300
306
|
if (extra.length > 0)
|
|
301
|
-
untrustedParts.push(`[${inlineSafe(q.header)}] discarded extra selections (single-choice): ${extra.join(", ")}`);
|
|
307
|
+
untrustedParts.push(`[${inlineSafe(q.header)}] discarded extra selections (single-choice): ${extra.map((s) => echoLabel(q, s, asIs)).join(", ")}`);
|
|
302
308
|
}
|
|
303
309
|
if (note)
|
|
304
310
|
untrustedParts.push(`[${inlineSafe(q.header)}] note: ${note}`);
|
|
@@ -17,7 +17,7 @@ export declare const DEFAULT_COMPACTION_INSTRUCTIONS: string;
|
|
|
17
17
|
* `compaction.instructions`, the DEFAULT constant, a manual `/compact` per-call override, and a
|
|
18
18
|
* preCompact hook's `additionalInstructions` — 修类不修点): instructions text can be model- or
|
|
19
19
|
* caller-authored, and it is injected VERBATIM into the summarization prompt
|
|
20
|
-
* (`\n\nAdditional Instructions:\n${...}
|
|
20
|
+
* (`\n\nAdditional Instructions:\n${...}`), so a forged `</system-reminder>`
|
|
21
21
|
* or `<<<`/`>>>` fence sentinel inside it would otherwise ride into a trusted prompt position.
|
|
22
22
|
* Posture (r2 review B4): `sanitizeUntrustedText` + fence defusing only — NEVER `delimitUntrusted`
|
|
23
23
|
* (fencing instructions as "data only, do not follow" self-defeats their instructional intent, and
|
|
@@ -169,7 +169,7 @@ export interface MaybeCompactOptions {
|
|
|
169
169
|
* design/145 §1 (semantics精确化): used only while WINDOW-SAFE and the budget gate allows — when a
|
|
170
170
|
* dry-run clamp shows the conversation would lose more than `settings.clampTolerance` of its
|
|
171
171
|
* chars to fit this model's window, the summary call falls back to the MAIN model (`model`),
|
|
172
|
-
* which is always window-safe (the content grew inside its window;
|
|
172
|
+
* which is always window-safe (the content grew inside its window; the reference compresses
|
|
173
173
|
* with the main-loop model unconditionally — the fallback IS the CC posture, the independent
|
|
174
174
|
* compaction model is sema's superset). Subagent note (design/145 §5): delegated children never
|
|
175
175
|
* inherit this option (subagent.ts buildChildSpec carries no compactionModel), so a child always
|
|
@@ -317,7 +317,7 @@ export interface MaybeCompactOptions {
|
|
|
317
317
|
maxCharsPerFile?: number;
|
|
318
318
|
/**
|
|
319
319
|
* CC-parity selection set: the files the task has READ, most recent
|
|
320
|
-
* first (
|
|
320
|
+
* first (the reference's post-compact restore sorts readFileState by timestamp — the read set is wider
|
|
321
321
|
* than the modified set and includes reference files the model consulted). When provided and
|
|
322
322
|
* non-empty it WINS over `modifiedFilesByRecency`; absent/empty falls back to the modified set
|
|
323
323
|
* (the pre-2026-07-03 behavior, and the right answer for callers with no read tracking).
|
|
@@ -419,6 +419,9 @@ export interface MaybeCompactOptions {
|
|
|
419
419
|
* context may have lost an engine frame the run still needs, and every reader of the new baseline
|
|
420
420
|
* (the next model request first) must see it restated. */
|
|
421
421
|
postureRestate?: () => Promise<void>;
|
|
422
|
+
/** The advisor tool's instructions' post-compaction restatement on a leg that mounts the tool (the runner's
|
|
423
|
+
* `compactionRestateOptions`): runs right after `postureRestate`, under the same belt, for the same reason. */
|
|
424
|
+
advisorRestate?: () => Promise<void>;
|
|
422
425
|
/**
|
|
423
426
|
* Fixed per-request prompt overhead (system prompt + tool schemas, in tokens), applied ONLY in the
|
|
424
427
|
* anchor-less regime (design/64 §26.7, search [91] fourth candidate): when no assistant in the
|
|
@@ -458,7 +461,7 @@ export interface MaybeCompactOptions {
|
|
|
458
461
|
* (`reused`) and feeds it back via this option; core treats `summaryProvider` as if absent for that one
|
|
459
462
|
* boundary when `consecutiveProviderReuse >= maxConsecutiveProviderReuse`. Default `3`, a
|
|
460
463
|
* SEMA choice — the earlier "(CC parity)" label was unsupported and is withdrawn (anchoring
|
|
461
|
-
* re-check 2026-08-23:
|
|
464
|
+
* re-check 2026-08-23: the reference has no external summary provider and no reuse concept at all;
|
|
462
465
|
* its three 3s are the PTL retry cap `b$d`, the consecutive-compaction-failure breaker `C$d` and
|
|
463
466
|
* the rapid-refill trip `Q3u`, none of them this). 3 is picked for the same reason those are: a
|
|
464
467
|
* small bound on how long a degraded path may keep answering before the real one is forced.
|
|
@@ -801,8 +804,8 @@ export declare function countSummarizedCrossSessionMessages(branch: ReadonlyArra
|
|
|
801
804
|
* SEMA-ONLY DEFENSE, not a CC port — but the ORIGINAL justification for that label was wrong
|
|
802
805
|
* on both of its premises, and the corrected pair still supports it. (a) "CC's full compact
|
|
803
806
|
* keeps tail 0 and monotonically shrinks" describes the `GNo` branch, which a LOCAL threshold
|
|
804
|
-
* compaction never reaches (
|
|
805
|
-
* pipeline, which preserves the last group verbatim
|
|
807
|
+
* compaction never reaches (the reference routes local passes to the reactive
|
|
808
|
+
* pipeline, which preserves the last group verbatim); the reference's
|
|
806
809
|
* default posture therefore has a keep-tail, exactly as ours does. (b) "CC has no
|
|
807
810
|
* request-layer trim" holds only for the MAIN conversation request: CC does own a
|
|
808
811
|
* keep-the-newest-groups-that-fit primitive (`UPb` :645223), whose only caller is the
|
|
@@ -819,7 +822,7 @@ export declare function nextTrimForceBackoff(prev: boolean, comp: {
|
|
|
819
822
|
freedTokens?: number;
|
|
820
823
|
naturalTrigger?: boolean;
|
|
821
824
|
}, trimForced?: boolean): boolean;
|
|
822
|
-
/** design/119 S3 (
|
|
825
|
+
/** design/119 S3 (rapid_refill_breaker): mutable per-task refill tracking state. */
|
|
823
826
|
export interface RapidRefillState {
|
|
824
827
|
lastCompactionTurn: number;
|
|
825
828
|
count: number;
|
|
@@ -827,7 +830,7 @@ export interface RapidRefillState {
|
|
|
827
830
|
/** Fresh tracking state (no compaction seen yet). */
|
|
828
831
|
export declare function createRapidRefillState(): RapidRefillState;
|
|
829
832
|
/**
|
|
830
|
-
* design/119 S3 (
|
|
833
|
+
* design/119 S3 (rapid_refill_breaker): record that a compaction just
|
|
831
834
|
* happened at `turn` and report whether the thrash breaker should TRIP. A compaction landing within
|
|
832
835
|
* `minGapTurns` of the previous one is a "rapid refill"; `tripAt` consecutive rapid refills = the
|
|
833
836
|
* context is dominated by incompressible content and further compaction only burns summary calls.
|
|
@@ -504,9 +504,11 @@ export async function maybeCompact(opts) {
|
|
|
504
504
|
catch {
|
|
505
505
|
}
|
|
506
506
|
}
|
|
507
|
-
|
|
507
|
+
for (const restate of [opts.postureRestate, opts.advisorRestate]) {
|
|
508
|
+
if (restate === undefined)
|
|
509
|
+
continue;
|
|
508
510
|
try {
|
|
509
|
-
await
|
|
511
|
+
await restate();
|
|
510
512
|
}
|
|
511
513
|
catch {
|
|
512
514
|
}
|
|
@@ -18,7 +18,7 @@ export declare const AUTO_MODE_ARMING_RECIPE_VERSION = 2;
|
|
|
18
18
|
export interface AutoModeArmingRecipe {
|
|
19
19
|
/** {@link AUTO_MODE_ARMING_RECIPE_VERSION}. An unknown version is refused, never partially read. */
|
|
20
20
|
v: number;
|
|
21
|
-
/** `buildAutoModePrompt` rule overrides for the four paired sections (omitted =
|
|
21
|
+
/** `buildAutoModePrompt` rule overrides for the four paired sections (omitted = the defaults). */
|
|
22
22
|
rules?: AutoModeRules;
|
|
23
23
|
/** Settings-plane deny rules rendered into `<settings_deny_rules>`. */
|
|
24
24
|
settingsDenyRules?: readonly string[];
|
|
@@ -37,7 +37,7 @@ export interface AutoModeArmingRecipe {
|
|
|
37
37
|
/** Classify round-trip cap, ms. */
|
|
38
38
|
timeoutMs?: number;
|
|
39
39
|
/**
|
|
40
|
-
* The classifier DENIAL-LIMIT bounds (`RunnerDeps.autoMode.denialLimit
|
|
40
|
+
* The classifier DENIAL-LIMIT bounds (`RunnerDeps.autoMode.denialLimit`):
|
|
41
41
|
* how many blocks the ancestor's classifier was allowed before a person had to look, and the window the
|
|
42
42
|
* fallback ask ran under. A KNOB triple, not prompt body — every member is orderable, so the fold takes
|
|
43
43
|
* the strictest of the two sides rather than refusing on a difference.
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
* `RunnerDeps.autoMode.timeoutMs` is omitted. Sized for a self-hosted gateway, not a cloud API: a
|
|
4
4
|
* thinking-by-default gateway answers a classification in 5–165 s (Qwen 3.8 p50 11–24 s, kimi and GLM p50
|
|
5
5
|
* ~10 s), and queueing plus prefill of 2–5 min is a normal wait on such a gateway (`docs/TIMEOUTS.md`). 180 s
|
|
6
|
-
* clears the slowest classification observed with margin;
|
|
6
|
+
* clears the slowest classification observed with margin; the reference's per-attempt base is 60 s (
|
|
7
7
|
* stretched to 120 s with prompt size). Worst-case walk = this × rungs (2) = 360 s. Where the leg has an
|
|
8
8
|
* approval seat a rung that runs out of time costs a question to a person, not a refusal (see the gate's
|
|
9
9
|
* classifier station).
|
|
10
10
|
*/
|
|
11
11
|
export declare const AUTO_MODE_DEFAULT_TIMEOUT_MS = 180000;
|
|
12
12
|
/**
|
|
13
|
-
* The classifier call's transient retry budget — the reference implementation's short ladder
|
|
13
|
+
* The classifier call's transient retry budget — the reference implementation's short ladder: a
|
|
14
14
|
* provider error (an HTTP 5xx, a dropped connection) is retried this many times inside the rung's budget, then the rung
|
|
15
15
|
* reports `unavailable` / `error`. Where the leg has an approval seat that question goes to a person, so a long ladder
|
|
16
16
|
* would only make the person wait out the rung's budget and hear "timed out" for a failure that was not one.
|
|
@@ -52,8 +52,8 @@ export declare const AUTO_MODE_CLASSIFIER_MAX_TOKENS = 256;
|
|
|
52
52
|
* which on a default-on gateway is a think). The seat pays for the least the wire can grade plus the verdict,
|
|
53
53
|
* never for an open-ended budget.
|
|
54
54
|
*
|
|
55
|
-
* 2048 is anchored twice:
|
|
56
|
-
* its `rejects_disabled_thinking` family
|
|
55
|
+
* 2048 is anchored twice: the reference adds exactly this many tokens to the verdict cap for a model in
|
|
56
|
+
* its `rejects_disabled_thinking` family; and it is 2 × `MIN_THINKING_TOKENS` (1024), so
|
|
57
57
|
* on the anthropic BUDGET path a HARD cap of 256 + 2048 clears the cap-wins skip (`budgetCapSkipsThinking`)
|
|
58
58
|
* and hosts a legal `low` budget (`1024 ≤ budget_tokens < max_tokens`) without the brain having to raise a
|
|
59
59
|
* cap it refuses to raise. Live 2026-09-15: deepseek's default think fits it ~90–100% of the time; the tail
|
|
@@ -62,8 +62,8 @@ export declare const AUTO_MODE_CLASSIFIER_MAX_TOKENS = 256;
|
|
|
62
62
|
*/
|
|
63
63
|
export declare const AUTO_MODE_CLASSIFIER_LOW_REASONING_BUDGET_TOKENS = 2048;
|
|
64
64
|
/**
|
|
65
|
-
* The RE-ASK seat's allowance — the room a rung gets ONCE after its first attempt produced no verdict:
|
|
66
|
-
*
|
|
65
|
+
* The RE-ASK seat's allowance — the room a rung gets ONCE after its first attempt produced no verdict: the reference's
|
|
66
|
+
* stage-2 classifier cap (`max_tokens: 8192 + bn`). Live 2026-09-15 the thinking tail that overruns
|
|
67
67
|
* 2048 (deepseek 1–2 of 20, some past 4096; Qwen up to 6k) sits under it. One re-ask, never a loop.
|
|
68
68
|
*/
|
|
69
69
|
export declare const AUTO_MODE_CLASSIFIER_THINK_BUDGET_TOKENS = 8192;
|
|
@@ -78,14 +78,14 @@ export declare const AUTO_MODE_CLASSIFIER_CONTRACT_BROKEN_AFTER = 2;
|
|
|
78
78
|
* recipe canonicalizer needs its VALUE and must not load the assembly face (and its SHA-locked assets)
|
|
79
79
|
* to get it; `auto-mode-prompt.js` re-exports it, so the public name and its module face are unchanged. */
|
|
80
80
|
export declare const AUTO_MODE_DEFAULTS_SENTINEL = "$defaults";
|
|
81
|
-
/**
|
|
81
|
+
/** The classifier DENIAL LIMITS applied when
|
|
82
82
|
* `RunnerDeps.autoMode.denialLimit` omits a bound. Count-then-judge: the block that reaches a bound is
|
|
83
83
|
* itself the one that falls back to a person (the 3rd consecutive block asks; the 20th total asks). */
|
|
84
84
|
export declare const AUTO_MODE_DENIAL_LIMIT_DEFAULTS: Readonly<{
|
|
85
85
|
maxConsecutive: number;
|
|
86
86
|
maxTotal: number;
|
|
87
87
|
}>;
|
|
88
|
-
/**
|
|
88
|
+
/** The fallback ask's auto-deny window (ms) when `autoDenyAfterMs` is omitted.
|
|
89
89
|
* `0` disarms the window (the ask waits on the approver alone — the upstream original "fall back to
|
|
90
90
|
* prompting" shape). */
|
|
91
91
|
export declare const AUTO_MODE_DENIAL_AUTO_DENY_DEFAULT_MS = 120000;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/** The auto-mode classifier SYSTEM prompt shell (
|
|
2
|
-
* principle 7 at its
|
|
1
|
+
/** The auto-mode classifier SYSTEM prompt shell (`auto_mode_system_prompt`, with consent-bar
|
|
2
|
+
* principle 7 at its later text — see the header note).
|
|
3
3
|
* Contains two assembly placeholders consumed by `buildAutoModePrompt`: `<permissions_template>`
|
|
4
4
|
* (replaced by the permissions document) and `<cross_session_messages_rule>` (replaced with "" —
|
|
5
5
|
* the 206/207 default). */
|
|
6
6
|
export declare const AUTO_MODE_BASE_PROMPT: string;
|
|
7
|
-
/** The external permissions document (
|
|
7
|
+
/** The external permissions document (`permissions_external`). Four PAIRED placeholder
|
|
8
8
|
* tags wrap the DEFAULT rule sets (environment / hard deny / soft deny / allow) and one UNPAIRED tag
|
|
9
9
|
* (`<settings_deny_rules>`) marks the settings-plane deny injection point — all consumed by
|
|
10
10
|
* `buildAutoModePrompt` with the CC-exact merge semantics (user rules REPLACE the defaults; the
|
|
@@ -7,7 +7,7 @@ import type { Message } from "../internal/llm.js";
|
|
|
7
7
|
export { AUTO_MODE_DEFAULTS_SENTINEL } from "./auto-mode-defaults.js";
|
|
8
8
|
/** Deployment-authored rule overrides for the four paired sections of the permissions document.
|
|
9
9
|
* Each entry is ONE rule (rendered as a `- ` bullet); omit a field (or pass an empty array) to keep
|
|
10
|
-
* the
|
|
10
|
+
* the default rules for that section. */
|
|
11
11
|
export interface AutoModeRules {
|
|
12
12
|
allow?: readonly string[];
|
|
13
13
|
softDeny?: readonly string[];
|
package/dist/core/auto-mode.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export declare function isAutoModeUnavailableCause(v: unknown): v is AutoModeUna
|
|
|
16
16
|
* HOW a reply failed to carry a verdict — the closed set behind `parse_error.form`. `missing` = the reader found
|
|
17
17
|
* NO answer (empty text, prose, an answer only inside a thinking block); `conflict` = it found TWO distinct
|
|
18
18
|
* `<block>` answers (raw or thinking-stripped). The split decides who gets a SECOND ATTEMPT at the same
|
|
19
|
-
* question, on both seats that offer one: a missing answer is asked for again (
|
|
19
|
+
* question, on both seats that offer one: a missing answer is asked for again (the reference re-asks an
|
|
20
20
|
* unparseable reply) and handed on to the next candidate ({@link rungDidNotRule}); a conflict gets neither —
|
|
21
21
|
* it carries a `yes`, and any second attempt that answered `no` would erase it. One rule, two seats: whatever
|
|
22
22
|
* a re-ask may not overwrite, a later rung may not overwrite either. Not on any wire face; the trace frame and
|
|
@@ -157,7 +157,7 @@ export declare function autoModeRoundNotAsked(reason: unknown): Error & {
|
|
|
157
157
|
*/
|
|
158
158
|
export declare function rungDidNotRule(v: AutoModeVerdict): AutoModeFallbackCause | undefined;
|
|
159
159
|
/**
|
|
160
|
-
* The model-facing deny text for an `unavailable` verdict —
|
|
160
|
+
* The model-facing deny text for an `unavailable` verdict — with the parenthetical
|
|
161
161
|
* spells for the causes this engine distinguishes (a wall-clock / connection timeout reads " (timed out)";
|
|
162
162
|
* an unknown kind reads nothing). The subject is the classifier itself rather than a model id: without a
|
|
163
163
|
* candidate ladder the decider cannot vouch for a name. One writer for every deny site. ROOT CAUSE, when
|
|
@@ -173,8 +173,8 @@ export declare function classifierUnavailableDenyMessage(toolName: string, cause
|
|
|
173
173
|
*/
|
|
174
174
|
export declare function classifierNoRulingAskMessage(askText: string, cause: AutoModeFallbackCause): string;
|
|
175
175
|
/**
|
|
176
|
-
* The model-facing deny text for a `parse_error` verdict —
|
|
177
|
-
* this action and is blocking it for safety"
|
|
176
|
+
* The model-facing deny text for a `parse_error` verdict — stem ("Auto mode could not evaluate
|
|
177
|
+
* this action and is blocking it for safety"): the classifier answered, but not with a verdict,
|
|
178
178
|
* and auto mode blocks what it could not evaluate. With a candidate ladder wired the tail NAMES the model whose
|
|
179
179
|
* reply carried no verdict (`attribution.modelUsed`) — a declared departure from upstream, whose card names no
|
|
180
180
|
* model: the person reading this card is the one who can change the catalog, and on a single-model deployment
|
|
@@ -183,8 +183,8 @@ export declare function classifierNoRulingAskMessage(askText: string, cause: Aut
|
|
|
183
183
|
*/
|
|
184
184
|
export declare function classifierParseFailureDenyMessage(attribution?: AutoModeClassifierRound): string;
|
|
185
185
|
/**
|
|
186
|
-
* Parse the classifier's output contract — the
|
|
187
|
-
* reason reader
|
|
186
|
+
* Parse the classifier's output contract — the verdict reader (with its thinking strip and its
|
|
187
|
+
* reason reader), plus ONE arm of sema's own:
|
|
188
188
|
* blocked: `<block>yes</block><category>Rule Name</category><reason>[Rule Name] …</reason>`
|
|
189
189
|
* allowed: `<block>no</block>`
|
|
190
190
|
*
|
|
@@ -212,7 +212,7 @@ export declare function classifierParseFailureDenyMessage(attribution?: AutoMode
|
|
|
212
212
|
* line from the tool name in that case. Downgrading a stated block to `parse_error` would lose the
|
|
213
213
|
* classifier's explicit verdict on the exact calls it flagged.
|
|
214
214
|
*
|
|
215
|
-
* `parse_error` is fail-closed: the gate handles it as a BLOCK (
|
|
215
|
+
* `parse_error` is fail-closed: the gate handles it as a BLOCK (the reference's own outcome for a reply with no
|
|
216
216
|
* verdict) that the denial limit counts like any other — never a silent allow, and never a question handed
|
|
217
217
|
* to a person on the classifier's behalf.
|
|
218
218
|
*/
|
|
@@ -340,8 +340,15 @@ export interface DenialLimitCounts {
|
|
|
340
340
|
/** Total blocks this run INCLUDING the one that tripped the bound (read before the total-bound reset). */
|
|
341
341
|
readonly total: number;
|
|
342
342
|
/** Which bound tripped. */
|
|
343
|
-
readonly limit:
|
|
343
|
+
readonly limit: DenialLimitBound;
|
|
344
344
|
}
|
|
345
|
+
/** The two denial bounds, spelled once: {@link DenialLimitBound} is derived from this tuple, and every reader of a
|
|
346
|
+
* stored or foreign fallback member judges its `limit` word through {@link isDenialLimitBound}. */
|
|
347
|
+
export declare const DENIAL_LIMIT_BOUNDS: readonly ["consecutive", "total"];
|
|
348
|
+
/** Which denial bound tripped: `consecutive` blocks in a row, or the run's `total`. */
|
|
349
|
+
export type DenialLimitBound = (typeof DENIAL_LIMIT_BOUNDS)[number];
|
|
350
|
+
/** Whether a value is one of {@link DENIAL_LIMIT_BOUNDS} — the screen a reader applies to a stored `limit` word. */
|
|
351
|
+
export declare function isDenialLimitBound(v: unknown): v is DenialLimitBound;
|
|
345
352
|
/**
|
|
346
353
|
* The DECISION-layer member of a denial-limit fallback ask (`PermissionResult` ask arm): the counts
|
|
347
354
|
* that tripped the bound, and NOTHING about a window. A window is a fact of the ask's ROUTE — a live
|
|
@@ -386,7 +393,8 @@ export type DenialLimitFallbackFace = UnarmedDenialLimitFallback | DenialLimitFa
|
|
|
386
393
|
* finite non-negative window), nothing else carried. A deployment-written row (a checkpoint store is a
|
|
387
394
|
* host's) can hold any shape; the faces that echo it (the inbox summary) read through here, so a bad
|
|
388
395
|
* shape reads as ABSENT rather than reaching a consumer as a malformed card. Not a parser of intent —
|
|
389
|
-
* `"3"` is not 3.
|
|
396
|
+
* `"3"` is not 3. The value is a plain record (no member comes from a prototype it was given); each member is read once,
|
|
397
|
+
* in declaration order, and the answer is the values judged.
|
|
390
398
|
*/
|
|
391
399
|
export declare function readDenialLimitFallback(v: unknown): DenialLimitFallback | undefined;
|
|
392
400
|
/** The window-less route's member, spelled in ONE place: every station that hands a fallback somewhere
|
package/dist/core/auto-mode.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AUTO_MODE_DEFAULT_TIMEOUT_MS, AUTO_MODE_DENIAL_AUTO_DENY_DEFAULT_MS, AUTO_MODE_DENIAL_LIMIT_DEFAULTS } from "./auto-mode-defaults.js";
|
|
2
2
|
import { thrownIs } from "./thrown-value.js";
|
|
3
3
|
import { describeRejectedValue } from "./tool-search-setting.js";
|
|
4
|
+
import { isPlainRecord } from "./mods/kernel/receive.js";
|
|
4
5
|
export const AUTO_MODE_UNAVAILABLE_CAUSES = Object.freeze(["error", "timeout"]);
|
|
5
6
|
const AUTO_MODE_UNAVAILABLE_CAUSE_SET = new Set(AUTO_MODE_UNAVAILABLE_CAUSES);
|
|
6
7
|
export function isAutoModeUnavailableCause(v) {
|
|
@@ -312,16 +313,18 @@ class AutoModeTimeout extends Error {
|
|
|
312
313
|
}
|
|
313
314
|
}
|
|
314
315
|
const isAutoModeTimeout = (e) => thrownIs(e, AutoModeTimeout);
|
|
316
|
+
export const DENIAL_LIMIT_BOUNDS = Object.freeze(["consecutive", "total"]);
|
|
317
|
+
export function isDenialLimitBound(v) {
|
|
318
|
+
return DENIAL_LIMIT_BOUNDS.some((bound) => v === bound);
|
|
319
|
+
}
|
|
315
320
|
export function readDenialLimitFallback(v) {
|
|
316
|
-
if (
|
|
321
|
+
if (!isPlainRecord(v))
|
|
317
322
|
return undefined;
|
|
318
|
-
const o = v;
|
|
319
323
|
const count = (x) => typeof x === "number" && Number.isFinite(x) && x >= 0;
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if (o["limit"] !== "consecutive" && o["limit"] !== "total")
|
|
324
|
+
const [consecutive, total, limit, autoDenyAfterMs] = [v["consecutive"], v["total"], v["limit"], v["autoDenyAfterMs"]];
|
|
325
|
+
if (!count(consecutive) || !count(total) || !count(autoDenyAfterMs) || !isDenialLimitBound(limit))
|
|
323
326
|
return undefined;
|
|
324
|
-
return { consecutive
|
|
327
|
+
return { consecutive, total, limit, autoDenyAfterMs };
|
|
325
328
|
}
|
|
326
329
|
export function unarmedWindow(fallback) {
|
|
327
330
|
return { ...countsOf(fallback), autoDenyAfterMs: 0 };
|