@sema-agent/core 7.51.1 → 7.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +550 -2
- package/dist/agents/agent-transcript-tool.d.ts +1 -1
- package/dist/agents/cascade.js +4 -0
- package/dist/agents/cumulative-stats.d.ts +3 -0
- package/dist/agents/cumulative-stats.js +3 -0
- package/dist/agents/list-agents-tool.d.ts +1 -1
- package/dist/agents/read-inbox-tool.d.ts +1 -1
- package/dist/agents/repair-loop.js +4 -0
- package/dist/agents/send-message-tool.d.ts +11 -16
- package/dist/agents/send-message-tool.js +11 -13
- package/dist/agents/subagent.d.ts +5 -0
- package/dist/agents/subagent.js +7 -4
- package/dist/agents/tool-filter.d.ts +40 -13
- package/dist/agents/tool-filter.js +28 -14
- package/dist/bench/metrics.d.ts +1 -0
- package/dist/brain/anthropic.js +16 -12
- package/dist/brain/model-presets.d.ts +4 -5
- package/dist/brain/model-presets.js +4 -4
- package/dist/brain/open-responses.js +16 -12
- package/dist/brain/openai.js +16 -12
- package/dist/brain/request-params.d.ts +12 -33
- package/dist/brain/request-params.js +5 -2
- package/dist/brain/request-route.d.ts +9 -8
- package/dist/brain/request-route.js +1 -0
- package/dist/brain/route-adjudicator.d.ts +117 -47
- package/dist/brain/route-adjudicator.js +171 -42
- package/dist/brain/route-conformance.js +2 -2
- package/dist/brain/status-sink.d.ts +18 -0
- package/dist/brain/status-sink.js +7 -0
- package/dist/core/allow-entry.d.ts +42 -8
- package/dist/core/allow-entry.js +24 -17
- package/dist/core/auto-compaction.d.ts +23 -20
- package/dist/core/auto-compaction.js +37 -16
- package/dist/core/auto-promote.d.ts +2 -1
- package/dist/core/auto-promote.js +2 -2
- package/dist/core/caller-tool-name.d.ts +9 -0
- package/dist/core/caller-tool-name.js +13 -0
- package/dist/core/checkpoint-requirements.d.ts +7 -1
- package/dist/core/checkpoint-requirements.js +2 -0
- package/dist/core/checkpoint-store.d.ts +36 -12
- package/dist/core/checkpoint-store.js +1 -1
- package/dist/core/child-clamp-seats.d.ts +6 -0
- package/dist/core/child-clamp-seats.js +2 -1
- package/dist/core/credential-vocabulary.d.ts +33 -8
- package/dist/core/credential-vocabulary.js +32 -7
- package/dist/core/decision-receipt.d.ts +2 -2
- package/dist/core/delegation-frames.d.ts +9 -2
- package/dist/core/delegation-name.d.ts +18 -0
- package/dist/core/delegation-name.js +47 -0
- package/dist/core/engine-capabilities.d.ts +8 -1
- package/dist/core/engine-capabilities.js +1 -1
- package/dist/core/engine-notice.d.ts +36 -19
- package/dist/core/frontmatter-fence.d.ts +10 -0
- package/dist/core/frontmatter-fence.js +6 -0
- package/dist/core/gate-fold.js +5 -23
- package/dist/core/gate-lanes.js +356 -270
- package/dist/core/governance-codes.d.ts +9 -4
- package/dist/core/governance-codes.js +9 -3
- package/dist/core/hooks.d.ts +276 -734
- package/dist/core/hooks.js +97 -192
- package/dist/{tools/fs → core}/image-admission.d.ts +21 -3
- package/dist/{tools/fs → core}/image-admission.js +24 -6
- package/dist/core/locked-config.d.ts +26 -5
- package/dist/core/locked-config.js +31 -6
- package/dist/core/mcp-connection-pool.d.ts +4 -1
- package/dist/core/mcp-connection-pool.js +7 -2
- package/dist/core/mcp-probe.d.ts +12 -9
- package/dist/core/mcp-probe.js +2 -2
- package/dist/core/mcp-server-spec.d.ts +53 -7
- package/dist/core/mcp-server-spec.js +84 -1
- package/dist/core/mcp.d.ts +11 -7
- package/dist/core/mcp.js +27 -9
- package/dist/core/memory-engine/data-plane.js +5 -1
- package/dist/core/memory-engine/distiller.js +16 -2
- package/dist/core/memory-engine/engine.d.ts +8 -11
- package/dist/core/memory-engine/engine.js +9 -5
- package/dist/core/memory-engine/frontmatter.d.ts +6 -0
- package/dist/core/memory-engine/frontmatter.js +19 -16
- package/dist/core/memory.d.ts +2 -2
- package/dist/core/mode-policy.d.ts +4 -0
- package/dist/core/mode-policy.js +7 -5
- package/dist/core/model-seat.d.ts +4 -1
- package/dist/core/mods/dollar.d.ts +109 -0
- package/dist/core/mods/dollar.js +154 -0
- package/dist/core/mods/host.d.ts +23 -0
- package/dist/core/mods/host.js +21 -0
- package/dist/core/mods/kernel/budget.d.ts +43 -0
- package/dist/core/mods/kernel/budget.js +83 -0
- package/dist/core/mods/kernel/dispatch.d.ts +100 -0
- package/dist/core/mods/kernel/dispatch.js +701 -0
- package/dist/core/mods/kernel/events.d.ts +242 -0
- package/dist/core/mods/kernel/events.js +210 -0
- package/dist/core/mods/kernel/index.d.ts +6 -0
- package/dist/core/mods/kernel/index.js +5 -0
- package/dist/core/mods/kernel/receive.d.ts +65 -0
- package/dist/core/mods/kernel/receive.js +123 -0
- package/dist/core/mods/kernel/registration.d.ts +131 -0
- package/dist/core/mods/kernel/registration.js +102 -0
- package/dist/core/mods/kernel/site-rules.d.ts +84 -0
- package/dist/core/mods/kernel/site-rules.js +104 -0
- package/dist/core/mods/stations.d.ts +350 -0
- package/dist/core/mods/stations.js +444 -0
- package/dist/core/own-property-receipt.js +11 -23
- package/dist/core/parent-spec-seat.d.ts +18 -7
- package/dist/core/parent-spec-seat.js +6 -2
- package/dist/core/path-identity.js +2 -1
- package/dist/core/permission-rule-syntax.d.ts +15 -0
- package/dist/core/permission-rule-syntax.js +24 -16
- package/dist/core/permission-rules.d.ts +7 -1
- package/dist/core/permission-rules.js +26 -15
- package/dist/core/prompt-section-seat.d.ts +15 -27
- package/dist/core/prompt-section-seat.js +73 -40
- package/dist/core/protocol-http-auth.d.ts +3 -1
- package/dist/core/protocol-http-auth.js +2 -0
- package/dist/core/reminder-mint.d.ts +2 -2
- package/dist/core/remote-env.d.ts +24 -12
- package/dist/core/remote-env.js +1 -0
- package/dist/core/resume-startup-cause.d.ts +16 -1
- package/dist/core/resume-startup-cause.js +4 -1
- package/dist/core/retired-keys.d.ts +4 -0
- package/dist/core/retired-keys.js +3 -0
- package/dist/core/runner/announce-once-ledger.d.ts +31 -1
- package/dist/core/runner/announce-once-ledger.js +22 -0
- package/dist/core/runner/assemble-result.d.ts +9 -0
- package/dist/core/runner/assemble-result.js +3 -1
- package/dist/core/runner/call-hook-stations.d.ts +23 -27
- package/dist/core/runner/call-hook-stations.js +58 -42
- package/dist/core/runner/caller-stop-gate.d.ts +25 -0
- package/dist/core/runner/caller-stop-gate.js +7 -0
- package/dist/core/runner/compaction-seams.d.ts +8 -22
- package/dist/core/runner/compaction-seams.js +28 -53
- package/dist/core/runner/construction-doors.js +11 -1
- package/dist/core/runner/contracts.d.ts +85 -83
- package/dist/core/runner/credential-origin-seat.d.ts +2 -0
- package/dist/core/runner/credential-origin-seat.js +19 -0
- package/dist/core/runner/extra-body-dropped-seat.d.ts +2 -6
- package/dist/core/runner/gate-exit.d.ts +47 -36
- package/dist/core/runner/gate-exit.js +8 -2
- package/dist/core/runner/image.js +1 -2
- package/dist/core/runner/inline-image.js +1 -1
- package/dist/core/runner/notice-seat-input.d.ts +11 -0
- package/dist/core/runner/notice-seat-input.js +1 -0
- package/dist/core/runner/person-path-rows.js +1 -0
- package/dist/core/runner/prepare-acquire-reconcile.js +5 -1
- package/dist/core/runner/prepare-ask-lane.d.ts +5 -7
- package/dist/core/runner/prepare-ask-lane.js +6 -15
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -2
- package/dist/core/runner/prepare-caps-and-workflow.js +25 -8
- package/dist/core/runner/prepare-config-doors.d.ts +5 -0
- package/dist/core/runner/prepare-config-doors.js +9 -0
- package/dist/core/runner/prepare-defer-classify.js +3 -4
- package/dist/core/runner/prepare-gate-stations.d.ts +8 -11
- package/dist/core/runner/prepare-gate-stations.js +11 -10
- package/dist/core/runner/prepare-inherited-gate.d.ts +8 -12
- package/dist/core/runner/prepare-inherited-gate.js +8 -21
- package/dist/core/runner/prepare-memory-engine-session.js +1 -1
- package/dist/core/runner/prepare-park-ask.js +10 -14
- package/dist/core/runner/prepare-policy-chain.d.ts +18 -16
- package/dist/core/runner/prepare-policy-chain.js +98 -101
- package/dist/core/runner/prepare-project-context.js +7 -10
- package/dist/core/runner/prepare-prompt-assembly.d.ts +45 -40
- package/dist/core/runner/prepare-prompt-assembly.js +134 -101
- package/dist/core/runner/prepare-prompt-inputs.d.ts +18 -19
- package/dist/core/runner/prepare-prompt-inputs.js +5 -7
- package/dist/core/runner/prepare-protocol-tools.d.ts +6 -4
- package/dist/core/runner/prepare-protocol-tools.js +2 -2
- package/dist/core/runner/prepare-safety-scan.js +6 -10
- package/dist/core/runner/prepare-suspend-saga.d.ts +6 -0
- package/dist/core/runner/prepare-suspend-saga.js +7 -5
- package/dist/core/runner/prepare-task.js +33 -15
- package/dist/core/runner/prepare-turn-wiring.d.ts +13 -15
- package/dist/core/runner/prepare-turn-wiring.js +29 -27
- package/dist/core/runner/prepare-wiring-manifest.d.ts +5 -6
- package/dist/core/runner/prepare-wiring-manifest.js +7 -7
- package/dist/core/runner/resume-apply.d.ts +5 -2
- package/dist/core/runner/resume-apply.js +24 -42
- package/dist/core/runner/resume-checkpoint-screen.d.ts +1 -0
- package/dist/core/runner/resume-checkpoint-screen.js +9 -1
- package/dist/core/runner/resume-preflight.js +38 -16
- package/dist/core/runner/retired-runner-deps.js +3 -1
- package/dist/core/runner/run-brain-sinks.d.ts +3 -2
- package/dist/core/runner/run-brain-sinks.js +5 -1
- package/dist/core/runner/run-compaction-machinery.d.ts +7 -1
- package/dist/core/runner/run-compaction-machinery.js +7 -33
- package/dist/core/runner/run-harness-handlers.js +4 -2
- package/dist/core/runner/run-identity-wiring.d.ts +3 -1
- package/dist/core/runner/run-identity-wiring.js +3 -2
- package/dist/core/runner/run-leg.js +62 -84
- package/dist/core/runner/run-notification-lane.js +1 -0
- package/dist/core/runner/run-recovery-lanes.d.ts +3 -0
- package/dist/core/runner/run-recovery-lanes.js +11 -10
- package/dist/core/runner/run-settle-and-teardown.js +9 -28
- package/dist/core/runner/run-stop-and-final-verify.js +18 -25
- package/dist/core/runner/run-terminal-adoption.d.ts +3 -0
- package/dist/core/runner/run-terminal-adoption.js +33 -22
- package/dist/core/runner/run-tool-mount-facts.js +5 -3
- package/dist/core/runner/run-turn-boundary.js +23 -34
- package/dist/core/runner/runtask.d.ts +6 -7
- package/dist/core/runner/runtask.js +14 -72
- package/dist/core/runner/session-rule-policy.d.ts +6 -4
- package/dist/core/runner/session-rule-policy.js +17 -10
- package/dist/core/runner/side-call-account.d.ts +68 -0
- package/dist/core/runner/side-call-account.js +61 -0
- package/dist/core/runner/stream-halt-verbs.js +12 -17
- package/dist/core/runner/stream-lifecycle-verbs.js +8 -5
- package/dist/core/runner/stream-steer-verb.d.ts +1 -1
- package/dist/core/runner/stream-steer-verb.js +20 -38
- package/dist/core/runner/sub-agent-deny-lists.d.ts +121 -22
- package/dist/core/runner/sub-agent-deny-lists.js +228 -71
- package/dist/core/runner/tool-end-body.d.ts +5 -6
- package/dist/core/runner/tool-end-body.js +6 -4
- package/dist/core/runner/tool-not-executed.d.ts +15 -0
- package/dist/core/runner/tool-not-executed.js +30 -0
- package/dist/core/runner/tool-occurrence.d.ts +8 -7
- package/dist/core/runner/tool-occurrence.js +5 -5
- package/dist/core/runner/tool-result-media-seat.d.ts +1 -1
- package/dist/core/runner-deps.d.ts +20 -28
- package/dist/core/safety-merge-corpus.js +18 -2
- package/dist/core/secret-env.d.ts +93 -20
- package/dist/core/secret-env.js +192 -38
- package/dist/core/session-policy-store.d.ts +93 -17
- package/dist/core/session-policy-store.js +178 -25
- package/dist/core/session-reconcile.d.ts +4 -0
- package/dist/core/session-reconcile.js +2 -1
- package/dist/core/shell-read-silence.js +3 -32
- package/dist/core/side-query.d.ts +5 -3
- package/dist/core/skill-grant.d.ts +3 -2
- package/dist/core/skill-grant.js +17 -9
- package/dist/core/skills-directory.d.ts +31 -11
- package/dist/core/skills-directory.js +655 -104
- package/dist/core/task-event.d.ts +13 -3
- package/dist/core/task-result.d.ts +8 -0
- package/dist/core/task-spec.d.ts +20 -19
- package/dist/core/task-stream.d.ts +14 -4
- package/dist/core/tighten-task-spec.d.ts +4 -3
- package/dist/core/tighten-task-spec.js +2 -4
- package/dist/core/tool-check-reading.d.ts +74 -0
- package/dist/core/tool-check-reading.js +80 -0
- package/dist/core/tool-policy.d.ts +59 -18
- package/dist/core/tool-policy.js +77 -12
- package/dist/core/tool-registry.d.ts +20 -0
- package/dist/core/tool-registry.js +4 -0
- package/dist/core/tool-spec.d.ts +10 -6
- package/dist/core/tools.js +2 -0
- package/dist/core/trace.d.ts +51 -32
- package/dist/core/types.d.ts +2 -1
- package/dist/core/types.js +1 -0
- package/dist/core/unc-spelling.d.ts +10 -0
- package/dist/core/unc-spelling.js +3 -0
- package/dist/core/untrusted-egress.d.ts +8 -0
- package/dist/core/untrusted-egress.js +4 -1
- package/dist/core/user-attachment.d.ts +12 -2
- package/dist/core/user-attachment.js +17 -2
- package/dist/core/wiring-manifest.d.ts +14 -13
- package/dist/core/wiring-manifest.js +2 -2
- package/dist/engine/compaction/utils.js +1 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +4 -3
- package/dist/engine/execution-env/symlink-chain.js +1 -1
- package/dist/engine/harness/agent-harness.d.ts +1 -1
- package/dist/engine/harness/agent-harness.js +3 -3
- package/dist/engine/harness/types.d.ts +17 -16
- package/dist/engine/harness/types.js +7 -1
- package/dist/engine/llm/types.d.ts +12 -7
- package/dist/engine/loop/agent-loop.js +1 -1
- package/dist/engine/loop/types.d.ts +1 -1
- package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
- package/dist/engine/session/import-validate.js +3 -10
- package/dist/engine/session/session.d.ts +4 -4
- package/dist/engine/session/session.js +4 -4
- package/dist/index.d.ts +24 -17
- package/dist/index.js +15 -12
- package/dist/internal/harness.d.ts +1 -1
- package/dist/internal/harness.js +1 -1
- package/dist/orchestration/run-spec.d.ts +4 -6
- package/dist/orchestration/run-spec.js +39 -63
- package/dist/orchestration/run-workflow-tool.js +1 -2
- package/dist/orchestration/workflow.d.ts +11 -3
- package/dist/orchestration/workflow.js +11 -2
- package/dist/prompt-assembly/artifact-store.d.ts +37 -56
- package/dist/prompt-assembly/artifact-store.js +31 -49
- package/dist/prompt-assembly/artifact.d.ts +89 -76
- package/dist/prompt-assembly/artifact.js +167 -146
- package/dist/prompt-assembly/assemble.d.ts +34 -29
- package/dist/prompt-assembly/assemble.js +33 -220
- package/dist/prompt-assembly/bands.d.ts +20 -0
- package/dist/prompt-assembly/bands.js +18 -0
- package/dist/prompt-assembly/catalog/constitution.d.ts +23 -0
- package/dist/prompt-assembly/catalog/constitution.js +69 -0
- package/dist/prompt-assembly/catalog/core-behavior.d.ts +9 -0
- package/dist/prompt-assembly/catalog/core-behavior.js +85 -0
- package/dist/prompt-assembly/catalog/index.d.ts +11 -0
- package/dist/prompt-assembly/catalog/index.js +59 -0
- package/dist/prompt-assembly/catalog/modes.d.ts +15 -0
- package/dist/prompt-assembly/catalog/modes.js +137 -0
- package/dist/prompt-assembly/catalog/role.d.ts +10 -0
- package/dist/prompt-assembly/catalog/role.js +157 -0
- package/dist/prompt-assembly/catalog/schema.d.ts +124 -0
- package/dist/prompt-assembly/catalog/schema.js +25 -0
- package/dist/prompt-assembly/catalog/sections.d.ts +9 -0
- package/dist/prompt-assembly/catalog/sections.js +98 -0
- package/dist/prompt-assembly/catalog/team.d.ts +4 -0
- package/dist/prompt-assembly/catalog/team.js +258 -0
- package/dist/prompt-assembly/composer.d.ts +24 -28
- package/dist/prompt-assembly/composer.js +124 -46
- package/dist/prompt-assembly/epoch.d.ts +89 -79
- package/dist/prompt-assembly/epoch.js +115 -142
- package/dist/prompt-assembly/explain.d.ts +58 -34
- package/dist/prompt-assembly/explain.js +21 -24
- package/dist/prompt-assembly/overlay.d.ts +127 -0
- package/dist/prompt-assembly/overlay.js +301 -0
- package/dist/prompt-assembly/renderers.d.ts +21 -0
- package/dist/prompt-assembly/renderers.js +39 -0
- package/dist/prompt-assembly/section-usage.d.ts +3 -3
- package/dist/prompt-assembly/section-usage.js +1 -1
- package/dist/prompt-assembly/select.d.ts +56 -0
- package/dist/prompt-assembly/select.js +69 -0
- package/dist/prompt-assembly/sugar.d.ts +31 -0
- package/dist/prompt-assembly/sugar.js +20 -0
- package/dist/prompt-assembly/turn-snapshot.d.ts +3 -2
- package/dist/prompt-assembly/types.d.ts +45 -148
- package/dist/prompts/coordinator.d.ts +2 -21
- package/dist/prompts/coordinator.js +3 -255
- package/dist/prompts/cowork.d.ts +27 -16
- package/dist/prompts/cowork.js +2 -23
- package/dist/prompts/default.d.ts +38 -500
- package/dist/prompts/default.js +20 -285
- package/dist/prompts/supervisor.d.ts +6 -71
- package/dist/prompts/supervisor.js +6 -117
- package/dist/stores/file/session-policy-store.d.ts +3 -3
- package/dist/tools/fs/bash-readonly-classifier.d.ts +6 -5
- package/dist/tools/fs/dir-entries.d.ts +4 -2
- package/dist/tools/fs/dir-entries.js +16 -4
- package/dist/tools/fs/fs-bash.d.ts +1 -1
- package/dist/tools/fs/fs-bash.js +22 -11
- package/dist/tools/fs/fs-pdf.js +17 -13
- package/dist/tools/fs/fs-read.js +4 -3
- package/dist/tools/fs/fs-shared.d.ts +1 -10
- package/dist/tools/fs/fs-shared.js +3 -4
- package/dist/tools/fs/fs-write.js +2 -1
- package/dist/tools/fs/notebook.js +1 -1
- package/dist/tools/fs/pdf.d.ts +20 -10
- package/dist/tools/fs/pdf.js +19 -10
- package/dist/tools/fs/program-read-model.d.ts +68 -8
- package/dist/tools/fs/program-read-model.js +112 -33
- package/dist/tools/fs/program-read-model.rows.js +30 -10
- package/dist/tools/fs/read-deny-home.d.ts +25 -9
- package/dist/tools/fs/read-deny-home.js +28 -27
- package/dist/tools/fs/read-deny.d.ts +41 -11
- package/dist/tools/fs/read-deny.js +51 -5
- package/dist/tools/fs/safety.d.ts +4 -26
- package/dist/tools/fs/safety.js +10 -32
- package/dist/tools/fs/search.js +15 -10
- package/dist/tools/fs/shell-read-argv.d.ts +3 -2
- package/dist/tools/fs/shell-read-argv.js +118 -38
- package/dist/tools/fs/shell-read-establish.d.ts +5 -5
- package/dist/tools/fs/shell-read-establish.js +11 -61
- package/dist/tools/fs/shell-read-identity.js +6 -3
- package/dist/tools/fs/shell-read-judge.d.ts +13 -15
- package/dist/tools/fs/shell-read-judge.js +18 -4
- package/dist/tools/fs/shell-read-plan.d.ts +2 -2
- package/dist/tools/web.js +1 -1
- package/package.json +13 -1
- package/test/export-surface.snapshot.json +256 -99
- package/wire-changes/core@7.51.1.json +5 -5
- package/wire-changes/core@7.51.2.json +293 -0
- package/wire-changes/core@7.52.0.json +5859 -0
- package/dist/core/hook-seats.d.ts +0 -66
- package/dist/core/hook-seats.js +0 -37
- package/dist/prompt-assembly/packs/sema-default.d.ts +0 -2
- package/dist/prompt-assembly/packs/sema-default.js +0 -147
- package/dist/prompts/simple-sections.d.ts +0 -58
- package/dist/prompts/simple-sections.js +0 -43
package/dist/core/hooks.d.ts
CHANGED
|
@@ -5,461 +5,213 @@ import type { CallTargetStamp } from "./effective-path-target.js";
|
|
|
5
5
|
import type { GateOutcome } from "./gate-outcome.js";
|
|
6
6
|
import { type PreToolUseScreening } from "./runner/gate-exit.js";
|
|
7
7
|
export { normalizeOrgGateVerdict, normalizePersistedRuleHit } from "./rule-lane-reads.js";
|
|
8
|
-
export { cloneObserverInput } from "./runner/gate-exit.js";
|
|
9
8
|
import { type AskClass } from "./ask-class.js";
|
|
10
9
|
import { type PermissionMode } from "./ask-origin.js";
|
|
11
10
|
import { type AutoModeDenialTracker } from "./auto-mode.js";
|
|
12
11
|
export { formatHookFeedback } from "./reminder-mint.js";
|
|
13
12
|
import type { WiringLegKind } from "./wiring-manifest.js";
|
|
14
|
-
import { type SafeNotifier } from "./safe-notify.js";
|
|
15
13
|
import type { PermissionSeatInputs } from "./mode-policy.js";
|
|
16
14
|
import type { SkillGateSeats } from "./skill-grant.js";
|
|
17
15
|
import type { AllowEntryGateSeats } from "./allow-entry.js";
|
|
18
16
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* The classic stations' faces and the two-phase tool gate. A deployment extends the engine through the mods bus
|
|
18
|
+
* (`RunnerDeps.mods` / `TaskSpec.mods`, `src/core/mods/`): each sema station raises one `classic.*` event, and the
|
|
19
|
+
* types here are those events' `e` shapes and answer forms. All feedback the model should see (a block reason,
|
|
20
|
+
* injected context) is wrapped as a `<system-reminder>` via {@link formatHookFeedback} so the model can read and
|
|
21
|
+
* self-correct.
|
|
21
22
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* submission (the task fails with a model-readable reason) or inject `additionalContext` ahead of it.
|
|
30
|
-
*
|
|
31
|
-
* The seam has since grown well past the trio — each later member carries its own contract below:
|
|
32
|
-
* {@link Hooks.stop} / {@link Hooks.stopFailure} (run-end pushback / API-error terminal observer),
|
|
33
|
-
* {@link Hooks.postToolUseFailure} and {@link Hooks.postToolBatch} (failure + batch-boundary taps),
|
|
34
|
-
* {@link Hooks.preCompact} / {@link Hooks.postCompact} (compaction gate + observer),
|
|
35
|
-
* {@link Hooks.permissionDenied} (deny observer), and the {@link Hooks.preToolUseObservational}
|
|
36
|
-
* declaration flag.
|
|
37
|
-
*
|
|
38
|
-
* All feedback the model should see (a block reason, injected context) is wrapped as a
|
|
39
|
-
* `<system-reminder>` via {@link formatHookFeedback} so the model can read and self-correct.
|
|
40
|
-
*
|
|
41
|
-
* **FAILURE POSTURE, and a correction to a widely-quoted anchor (recorded 2026-08-23).** Three repos
|
|
42
|
-
* have reasoned from the sentence "CC fails open on hook failures, exit code 2 excepted". That sentence
|
|
43
|
-
* is TRUE OF ONE LANE and false as a general statement, and the difference lands exactly on this seam.
|
|
44
|
-
* CC runs hooks of seven kinds; the `command` kind is a shell script, and for it a spawn failure, a
|
|
45
|
-
* non-zero exit and a per-hook timeout are all non-blocking — the call proceeds. But CC ALSO has an
|
|
46
|
-
* in-process CALLBACK lane, which is the one structurally equivalent to this interface, and there a
|
|
47
|
-
* PreToolUse callback that throws or times out is FAIL-CLOSED, with its own message stating that the
|
|
48
|
-
* tool call was not executed. (Two further details the short sentence hides: the decision channel is
|
|
49
|
-
* stdout JSON, with the exit code only a fallback — so exit 0 can block and a non-zero non-2 exit with
|
|
50
|
-
* valid JSON does not; and the callback lane's UserPromptSubmit timeout BLOCKS the prompt.)
|
|
51
|
-
*
|
|
52
|
-
* So this seam's fail-closed postures are not a sema invention to be justified against CC — they are
|
|
53
|
-
* the same posture CC takes on the same kind of lane: a `preToolUse` that throws or does not answer
|
|
54
|
-
* refuses the call, a `userPromptSubmit` that throws or does not answer refuses the prompt, and the
|
|
55
|
-
* OBSERVATION seats swallow and disclose because an observer has nothing to fail closed about. Anyone
|
|
56
|
-
* quoting the short sentence to argue this layer "should" fail open is quoting the script lane.
|
|
23
|
+
* **FAILURE POSTURE, and a correction to a widely-quoted anchor (recorded 2026-08-23).** "CC fails open on hook
|
|
24
|
+
* failures, exit code 2 excepted" is TRUE OF ONE LANE: CC's `command` hooks (shell scripts) are non-blocking on a
|
|
25
|
+
* spawn failure, a non-zero exit or a timeout. CC's in-process CALLBACK lane — the one structurally equivalent to a
|
|
26
|
+
* handler here — is FAIL-CLOSED on PreToolUse (a callback that throws or times out does not execute the call) and
|
|
27
|
+
* its UserPromptSubmit timeout BLOCKS the prompt. So the two decision events here (`classic.PreToolUse`,
|
|
28
|
+
* `classic.UserPromptSubmit`) refuse on a handler's failure (the event table's failure column), and the observation
|
|
29
|
+
* events skip the failed handler, because an observer has nothing to fail closed about.
|
|
57
30
|
*/
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
*
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
|
|
70
|
-
* `parentConstraintCount`. A deployment that flips on a default-OFF diagnostic tracer therefore also
|
|
71
|
-
* changes the shape every parked child's resume has to re-supply. The declaration is how a deployment
|
|
72
|
-
* says which of the two it wired, on the same footing as every other thing the library trusts a
|
|
73
|
-
* deployment to state about its own wiring.
|
|
74
|
-
*
|
|
75
|
-
* What does NOT change: the callback still runs in THIS task's own tool gate, on every call, with the
|
|
76
|
-
* same context and the same crash posture (a throw is still the fail-closed deny). Observation is
|
|
77
|
-
* untouched; only the inherited constraint goes away.
|
|
78
|
-
*
|
|
79
|
-
* The face also receives a DETACHED copy of the arguments rather than the live object, because the
|
|
80
|
-
* gate reads a rewrite off reference identity and an in-place edit would otherwise be a second channel
|
|
81
|
-
* that outlives the dropped return value. That detachment is BEST-EFFORT, in the same sense (and by the
|
|
82
|
-
* same helper) as every other observe-only payload here: a graph `structuredClone` cannot take — a
|
|
83
|
-
* function, a live handle — falls back to a shallow copy whose nested objects still alias, and a
|
|
84
|
-
* `SharedArrayBuffer` shares its memory even when the clone succeeds. Phase-1 arguments are the model's
|
|
85
|
-
* JSON on the ordinary path, which clones whole; the residual is reachable only through values a
|
|
86
|
-
* DEPLOYMENT put there (its own rewrite, or driving `runToolGate` directly), and the face and the
|
|
87
|
-
* deployment are one trust principal — this seam helps a deployment keep its own declaration, it is not
|
|
88
|
-
* a boundary against an untrusted party.
|
|
89
|
-
*
|
|
90
|
-
* If a declared-observational face RETURNS SOMETHING ANYWAY, the return is REFUSED, not obeyed: the
|
|
91
|
-
* call proceeds as if the hook had no opinion (`undefined`), and the deployment's `onError` face is
|
|
92
|
-
* told (`phase:"hook"`, classification `observational-hook-verdict-ignored`). That covers the whole
|
|
93
|
-
* result object — an `additionalContext` injection is a run-affecting capability too, so a face that
|
|
94
|
-
* declared it only watches does not get to write into the model's transcript either. The refusal is
|
|
95
|
-
* loud on purpose: a declaration that could be quietly contradicted would be a way to keep a
|
|
96
|
-
* screening face's verdicts while shedding the delegation constraint they belong to.
|
|
97
|
-
*/
|
|
98
|
-
preToolUseObservational?: true;
|
|
99
|
-
postToolUse?(toolName: string, input: unknown, output: HookToolOutput, ctx: HookToolContext): PostToolUseResult | undefined | Promise<PostToolUseResult | undefined>;
|
|
100
|
-
/**
|
|
101
|
-
* design/373 §4.3 (D2) ⚠️ WIDENED INVOCATION SET: this seat now screens EVERY user-lane entrance,
|
|
102
|
-
* not just the objective — a live `TaskStream.steer`, a wake resume's message (pre-CAS, at the
|
|
103
|
-
* verb), and a parked steer's resume redelivery (any draining resume kind) all pass through it, discriminated by
|
|
104
|
-
* {@link UserPromptSubmitContext.source}. A hook that blocks unconditionally therefore starts
|
|
105
|
-
* refusing steers too — branch on `ctx.source` (+ `ctx.actor`) to scope a verdict. The screen's
|
|
106
|
-
* domain is caller/operator PROSE only: engine-authored frames (task notifications, diagnostics,
|
|
107
|
-
* recall) never pass here — external `notify()` text takes the sanitized DATA-frame lane instead
|
|
108
|
-
* (ruled: notification frames are not prompts; see the notify contract). The same input can
|
|
109
|
-
* legally arrive twice under two sources (live + parked redelivery) — idempotency is the hook's,
|
|
110
|
-
* keyed on `ctx.inputId`. Block semantics per entrance: objective ⇒ the task ends `blocked`;
|
|
111
|
-
* live steer ⇒ typed `steering.blocked_by_hook` to the steer caller; resume message ⇒ typed
|
|
112
|
-
* pre-CAS refusal (the checkpoint stays pending); parked redelivery ⇒ the frame is withheld
|
|
113
|
-
* with a `steering.parked_input_blocked` notice + a `delivery:"blocked"` human_input account,
|
|
114
|
-
* and the resume itself proceeds (a blocked instruction must never wedge a wake).
|
|
115
|
-
*
|
|
116
|
-
* ⚠️ RE-ENTRANT within one leg: the steer verb goes live the moment the run's handle publishes —
|
|
117
|
-
* BEFORE the objective seat runs — so a steer screen can overlap the objective screen (and a
|
|
118
|
-
* resume-message screen, which fires pre-CAS at the verb) in flight. A stateful implementation
|
|
119
|
-
* (per-call temp files, a single in-flight latch, a shared accumulator) must tolerate concurrent
|
|
120
|
-
* entry; only steer-vs-steer is serialized. And that serialization has a LATENCY face: queued
|
|
121
|
-
* steers screen strictly FIFO, so each waits behind its predecessor's ENTIRE hook bound (the
|
|
122
|
-
* resolved `timeoutMs`, default 600s) — a slow or wedged screen delays every steer behind it by
|
|
123
|
-
* up to the full bound, which is a reason to declare a short `timeoutMs` on deployments that
|
|
124
|
-
* screen steers.
|
|
125
|
-
*/
|
|
126
|
-
userPromptSubmit?(prompt: string,
|
|
127
|
-
/** #281 件A (additive): the run/leg identity envelope — an implementation declaring only
|
|
128
|
-
* `(prompt)` keeps working. Always supplied on the engine's emission. design/373: carries the
|
|
129
|
-
* entrance discriminator (`source`/`inputId`/`actor`) — see {@link UserPromptSubmitContext}. */
|
|
130
|
-
ctx?: UserPromptSubmitContext): UserPromptSubmitResult | undefined | Promise<UserPromptSubmitResult | undefined>;
|
|
131
|
-
/**
|
|
132
|
-
* roadmap #5 (CC 198 Stop hook, :473831-): runs when the agent WOULD OTHERWISE END its run (no
|
|
133
|
-
* more tool calls, steering and follow-up queues dry). Return `{ block: reason }` to PUSH BACK —
|
|
134
|
-
* the reason is injected as a model-readable message and the run continues another turn (external
|
|
135
|
-
* adjudication: "the tests still fail", "the deliverable is missing X"). Return `undefined` to let
|
|
136
|
-
* the run end. Guardrails (CC-exact): consecutive blocks are capped (default 8 — the loop then
|
|
137
|
-
* overrides and ends with a warning); `ctx.stopHookActive` is true when the run is ALREADY
|
|
138
|
-
* continuing due to a previous block — a hook that ignores it and blocks unconditionally loops
|
|
139
|
-
* until the cap. `maxTurns` still outranks everything.
|
|
140
|
-
*/
|
|
141
|
-
stop?(ctx: StopHookContext): StopHookResult | undefined | Promise<StopHookResult | undefined>;
|
|
142
|
-
/**
|
|
143
|
-
* design/134 (CC PostToolUseFailure parity, SDK 0.3.202): runs after a tool EXECUTION fails —
|
|
144
|
-
* mutually exclusive with {@link postToolUse} (success → postToolUse; failure → this). Fires ONLY
|
|
145
|
-
* for genuine execution failures: a gate/policy block, a plan-mode deny, a pre-execution abort or a
|
|
146
|
-
* durable suspend triggers NEITHER callback (CC scopes those to the PermissionDenied event domain,
|
|
147
|
-
* not implemented here). Capability is additionalContext-only (CC-exact): the text is appended to
|
|
148
|
-
* the error tool result as a `<system-reminder>`; the failure itself cannot be rewritten.
|
|
149
|
-
*/
|
|
150
|
-
postToolUseFailure?(toolName: string, input: unknown, failure: HookToolFailure, ctx: HookToolContext): PostToolUseFailureResult | undefined | Promise<PostToolUseFailureResult | undefined>;
|
|
151
|
-
/**
|
|
152
|
-
* design/134 (CC PostToolBatch parity, SDK 0.3.202): fires ONCE after every tool call in a batch
|
|
153
|
-
* (one assistant turn's calls, design/120 stream-inline included) has resolved, before the next
|
|
154
|
-
* model request. Per-tool postToolUse/postToolUseFailure fire first; the batch callback fires after,
|
|
155
|
-
* at the turn boundary. A zero-tool turn does not fire; an aborted/steered-away boundary does not
|
|
156
|
-
* fire (same gate family as design/133 attachments). additionalContext is injected once for the
|
|
157
|
-
* whole batch as a boundary `<system-reminder>` (sanitized, shares the attachment byte cap).
|
|
158
|
-
*
|
|
159
|
-
* RB-467 (test-AI black-box repro, board 2305: ONE injection ate a whole subsequent batch): a batch
|
|
160
|
-
* landing on a boundary where the engine itself injected (final-verification nudge / finalize
|
|
161
|
-
* write-out) is now DELIVERED with `meta.injectedThisTurn` set, instead of being suppressed — for a
|
|
162
|
-
* deployment observer, any suppressed boundary is lost audit data; attribution belongs to the
|
|
163
|
-
* observer. On such a boundary the hook's `additionalContext` is IGNORED (the boundary already
|
|
164
|
-
* carries an engine injection; stacking observer text there is the double-inject this gate
|
|
165
|
-
* originally guarded against — that half of the old behavior stands).
|
|
166
|
-
*/
|
|
167
|
-
postToolBatch?(batch: PostToolBatchCall[], meta?: {
|
|
168
|
-
injectedThisTurn: "final_verification" | "finalize";
|
|
169
|
-
},
|
|
170
|
-
/** #281 件A (additive): the run/leg identity envelope, on its OWN parameter — `meta`'s presence
|
|
171
|
-
* is an existing signal ("the engine injected at this boundary") that must not become
|
|
172
|
-
* always-true just because identity rides along. Always supplied on the engine's emission. */
|
|
173
|
-
ctx?: PostToolBatchContext): PostToolBatchResult | undefined | Promise<PostToolBatchResult | undefined>;
|
|
174
|
-
/**
|
|
175
|
-
* design/134 (CC PreCompact parity): runs before each compaction, AFTER the trigger gate and a
|
|
176
|
-
* valid cut point are confirmed (so every preCompact corresponds to a compaction that would
|
|
177
|
-
* actually happen) and before the summary LLM call. `trigger`: "auto" (threshold) | "manual"
|
|
178
|
-
* (/compact) | "forced" (promptTooLong recovery and trim-pressure — compaction is not optional
|
|
179
|
-
* there). Return `{ block }` to skip this compaction (honored on auto/manual ONLY; ignored with a
|
|
180
|
-
* trace on forced — blocking a compaction the provider already demanded would kill the run).
|
|
181
|
-
* `additionalInstructions` is merged (appended) into the summarization instructions (CC
|
|
182
|
-
* mergeHookInstructions shape). A THROWING preCompact is swallowed on every path (traced, treated
|
|
183
|
-
* as no-block): an observer bug must never feed the compaction breaker or kill PTL recovery.
|
|
184
|
-
*/
|
|
185
|
-
preCompact?(ctx: PreCompactContext): PreCompactResult | undefined | Promise<PreCompactResult | undefined>;
|
|
186
|
-
/**
|
|
187
|
-
* design/134 (CC PostCompact parity): observe-only, after the compaction landed (summary appended
|
|
188
|
-
* to the session). No return capability (CC-exact); a throw is swallowed and traced.
|
|
189
|
-
*/
|
|
190
|
-
postCompact?(ctx: PostCompactContext): void | Promise<void>;
|
|
191
|
-
/**
|
|
192
|
-
* StopFailure (the last engine-owned event of the registry-core 0.1.51 hooks contract; CC semantics:
|
|
193
|
-
* "the turn ended because of an API error"). Fires ONCE, after the result is assembled, when the task
|
|
194
|
-
* terminates `failed` BECAUSE the model/API layer errored (a brain error terminal —
|
|
195
|
-
* auth / network / rate_limit / server_error / …). It does NOT fire for engine-owned failure classes:
|
|
196
|
-
* budget, timeout/abort, max-turns, degenerate/walltime cutoffs (deliberate engine cuts), storage
|
|
197
|
-
* conflict, blocked, or a durable suspend — those are not API errors. Observe-only (CC-exact: the
|
|
198
|
-
* contract defines no StopFailure output capability); a throwing callback is swallowed + traced
|
|
199
|
-
* (design/134 discipline — an observer bug must never rewrite a terminal state).
|
|
200
|
-
*/
|
|
201
|
-
stopFailure?(ctx: StopFailureContext): void | Promise<void>;
|
|
202
|
-
/**
|
|
203
|
-
* design/134 R5 (CC PermissionDenied parity, SDK 0.3.202): runs when the tool gate's
|
|
204
|
-
* adjudicate chain DENY-SHORT-CIRCUITS a tool call — a ToolPolicy deny, a gate tighten (egress /
|
|
205
|
-
* irreversibility / coarse shellGate) whose `ask` resolved to deny (headless auto-deny included), or the
|
|
206
|
-
* plan-mode write-deny. Closes the observation blind spot where a blocked call fires NEITHER postToolUse
|
|
207
|
-
* NOR postToolUseFailure (R3 scoping). Does NOT fire for:
|
|
208
|
-
* - a **durable suspend** (the ask path — CC surfaces that via a `can_use_tool` control_request);
|
|
209
|
-
* - a **PreToolUse hook deny** (CC-exact: "PreToolUse hook denies circumvention canUseTool and are not
|
|
210
|
-
* covered here").
|
|
211
|
-
* DOES fire for a **PreToolUse hook CRASH** (RB-442, `source:"hook"`): a throwing hook is intercepted by
|
|
212
|
-
* the ENGINE, which then makes its OWN fail-closed deny decision — likewise a hook result the decision
|
|
213
|
-
* receipt REFUSES (out of contract, undetachable). The R5 exclusion above covers the hook's own DENY
|
|
214
|
-
* DECISION — not an engine decision that merely happened near a hook.
|
|
215
|
-
* Observe-only v1 (CC-exact payload `{toolName, input, toolCallId, reason}` + our `source` enum standing
|
|
216
|
-
* in for CC `decision_reason_type`): no `retry` capability (recorded — retry semantics vs our adjudicate
|
|
217
|
-
* chain need their own design), no additionalContext. A throwing callback is swallowed + traced via
|
|
218
|
-
* `onError(phase:"hook")` — an observer bug must never alter the deny outcome (design/134 discipline).
|
|
219
|
-
*
|
|
220
|
-
* **HOW WIDE THIS SEAT IS, stated honestly (anchoring re-check 2026-08-23).** The exclusion sentence
|
|
221
|
-
* above is quoted from the SDK's TYPE-LEVEL documentation, and the whole R5 scoping argument was
|
|
222
|
-
* built on it without ever being checked against a shipped bundle. Against CC 2.1.223's runtime the
|
|
223
|
-
* picture is different in a way that matters for how this comment may be USED: CC emits its
|
|
224
|
-
* PermissionDenied event from exactly ONE site, guarded to the auto-mode CLASSIFIER's refusals —
|
|
225
|
-
* a rule deny, a mode deny and a headless auto-deny emit nothing at all. So "a hook's own deny is
|
|
226
|
-
* excluded" is TRIVIALLY true there (almost everything is excluded), and it must not be read as
|
|
227
|
-
* evidence that this seat's TRIGGER SURFACE matches CC's. It does not: sema fires on four engine
|
|
228
|
-
* emissions with seven `source` values, deliberately WIDER. The width is the useful direction for an
|
|
229
|
-
* observation seat — the blind spot R3 named is real and a narrower seat would not close it — and it
|
|
230
|
-
* is a divergence rather than a parity claim. The exclusion itself stays, on its own merit: a hook's
|
|
231
|
-
* deny is the HOOK's decision, and this seat exists to attribute the ENGINE's.
|
|
232
|
-
*/
|
|
233
|
-
permissionDenied?(payload: PermissionDeniedPayload): void | Promise<void>;
|
|
234
|
-
/**
|
|
235
|
-
* The TIME BOUND every seat on this object runs under, in milliseconds. Absent ⇒
|
|
236
|
-
* {@link DEFAULT_HOOK_TIMEOUT_MS}. It is the analog of the CC hook record's own `timeout` field —
|
|
237
|
-
* declared once per hook record there, once per hook OBJECT here, because this seam's record IS the
|
|
238
|
-
* object. The unit is ms rather than CC's seconds: every other deadline this library takes ends in
|
|
239
|
-
* `Ms`, and one unit per codebase beats one unit per upstream.
|
|
240
|
-
*
|
|
241
|
-
* **Why the seam has a bound at all.** Every callback above is DEPLOYMENT code awaited on the
|
|
242
|
-
* engine's critical path, and one that never returns used to stop the whole run — the tool gate
|
|
243
|
-
* awaited `preToolUse` bare, so a hung screening face left the call unsettled and the task's own
|
|
244
|
-
* timeout/cancel could not end it. The diagnosis was an internal asymmetry rather than a guess: the
|
|
245
|
-
* SAME callback installed as an inherited constraint on a delegated child was already bounded, because
|
|
246
|
-
* that path folds it into a `ToolPolicy` and the policy wait is abort-raced — and the sibling seam in
|
|
247
|
-
* this very file (`reversibilityProbe`) had already been given a default deadline for the identical
|
|
248
|
-
* reason. Policies were bounded, probes were bounded, hooks were not.
|
|
249
|
-
*
|
|
250
|
-
* **What a bound does NOT change.** A seat that answers keeps its answer, byte for byte; a seat that
|
|
251
|
-
* throws keeps its existing crash posture (this member changes nothing about a throw). The bound is
|
|
252
|
-
* consulted only when a seat has not answered yet, and what happens then is per-seat and stated on
|
|
253
|
-
* each member's own contract — decision seats fail CLOSED (`preToolUse` refuses the call the way a
|
|
254
|
-
* crash does; `userPromptSubmit` refuses the prompt), observation seats are ABANDONED and the engine
|
|
255
|
-
* proceeds as if the seat had returned nothing. Either way the deployment is told on its `onError`
|
|
256
|
-
* lane, because a silently-dropped seat is the failure mode this member exists to make visible.
|
|
257
|
-
*
|
|
258
|
-
* **The seat also gets a signal.** An expired wait would otherwise leave the callback running with
|
|
259
|
-
* nobody reading its answer — an orphan of the deployment's own making. So every context carries an
|
|
260
|
-
* optional `signal` that aborts when this bound elapses (or the task aborts), and an implementation
|
|
261
|
-
* that honors it can cancel the read it was waiting on. Honoring it is optional; a seat that ignores
|
|
262
|
-
* it is exactly as bounded as before, the engine simply stops waiting.
|
|
263
|
-
*
|
|
264
|
-
* **WHAT THE BOUND IS ON, stated narrowly because the difference is not academic.** It bounds the
|
|
265
|
-
* engine's WAIT, not the callback's CPU. A hook that blocks the thread SYNCHRONOUSLY — a spin loop, a
|
|
266
|
-
* synchronous exec, a synchronous parse of something enormous — cannot be preempted by this bound or
|
|
267
|
-
* by any other in-process mechanism, because the timer that would fire is queued behind the code that
|
|
268
|
-
* is not yielding; the ordering of the timer's installation makes no difference to that. In-process
|
|
269
|
-
* is the seam's whole premise (it is what makes a hook able to rewrite args and return a verdict),
|
|
270
|
-
* and preemption is what it trades away. A deployment that must survive a hook it does not trust to
|
|
271
|
-
* yield runs that hook somewhere with its own thread — a worker, a process, a service — and awaits
|
|
272
|
-
* the result from here. What this member DOES bound is every asynchronous wait, which is where the
|
|
273
|
-
* failure this was written for lives: a callback that awaits an unreachable host, a lock, a queue.
|
|
274
|
-
*
|
|
275
|
-
* **Value discipline** (bad values are loud, never silently reinterpreted): a non-finite, negative, or
|
|
276
|
-
* above-`setTimeout`-ceiling (2147483647) value is REFUSED to the default and reported on the
|
|
277
|
-
* deployment's error lane — the same treatment, and the same ceiling, the gate's `approvalTimeoutMs`
|
|
278
|
-
* seat gives its own garbage. `0` is honored as written (every seat expires immediately), because a
|
|
279
|
-
* deployment that writes zero has said something, and guessing that it meant "unbounded" would be the
|
|
280
|
-
* one reading this member cannot support.
|
|
281
|
-
*/
|
|
282
|
-
timeoutMs?: number;
|
|
31
|
+
/** The members every classic event's `e` carries for the leg it fires on. */
|
|
32
|
+
export interface ClassicEventBase {
|
|
33
|
+
/** The run/leg identity envelope — see {@link HookInvocationIdentity} for the presence law. */
|
|
34
|
+
readonly identity?: HookInvocationIdentity;
|
|
35
|
+
/** The delegated leg's id (its task id — the key its `task_progress` frames and its parent's fleet row use).
|
|
36
|
+
* Absent on a top-level leg. */
|
|
37
|
+
readonly agentId?: string;
|
|
38
|
+
/** The leg's EFFECTIVE permission mode when the event is raised — the mode seat's `observed` read (it arms no
|
|
39
|
+
* classifier). Absent where there is no leg seat: a host-driven {@link runToolGate}, the delegation-fold twin, the
|
|
40
|
+
* `"resume_message"` screen (before the resumed leg exists), and the compaction / StopFailure events (the
|
|
41
|
+
* reference's hook input omits it there). Not a version signal. */
|
|
42
|
+
readonly permissionMode?: PermissionMode;
|
|
283
43
|
}
|
|
284
44
|
/**
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
* deadline, and this ceiling is what ends it on a run that does not. A deployment whose hooks should
|
|
291
|
-
* answer in a second says so with `timeoutMs`.
|
|
292
|
-
*/
|
|
293
|
-
export declare const DEFAULT_HOOK_TIMEOUT_MS = 600000;
|
|
294
|
-
/** `setTimeout`'s own ceiling: above it the platform silently clamps to ~1ms, which would turn a
|
|
295
|
-
* deployment's "very long bound" into an instant expiry it never asked for. Refused loudly instead
|
|
296
|
-
* (same ceiling, same posture as the gate's `approvalTimeoutMs`). */
|
|
297
|
-
export declare const MAX_HOOK_TIMEOUT_MS = 2147483647;
|
|
298
|
-
/**
|
|
299
|
-
* How long an observation seat still gets when the task is cancelled `elapsed` ms into its wait — the
|
|
300
|
-
* grace, capped by what is LEFT of the declared deadline.
|
|
301
|
-
*
|
|
302
|
-
* The `remaining` argument, not the whole deadline, is the correction: arming a fresh
|
|
303
|
-
* `min(GRACE, timeoutMs)` from the abort moment restarts the clock, so an abort landing near the
|
|
304
|
-
* deadline pushes the seat's absolute end PAST the number the deployment declared — up to double it for
|
|
305
|
-
* a sub-second bound — on precisely the cancelled-task settlement path the grace exists to shorten. The
|
|
306
|
-
* two contract sentences this file already carries ("never an extension", "a deployment that declared a
|
|
307
|
-
* SHORTER `timeoutMs` keeps its own number") were true only in the aborted-on-entry case, where elapsed
|
|
308
|
-
* is zero and the two formulas coincide. Now they are true everywhere.
|
|
309
|
-
*
|
|
310
|
-
* Clamped at zero: a deadline already spent is no grace at all, not a negative timer.
|
|
45
|
+
* `classic.PreToolUse`'s `e` — raised before a tool executes (the gate's phase 1, the approved-edit re-screen, the
|
|
46
|
+
* resumed leg's re-screen of an approved call). Pinned: `tool`, `tool_use_id`, `agentId`, `input` (what a handler
|
|
47
|
+
* judges is what runs — a rewrite is the answer's `updatedInput`). Answer: {@link PreToolUseResult}; a handler with no
|
|
48
|
+
* opinion returns `next(e)`. A handler's `allow` does NOT circumvent the policy: the policy still runs on the (possibly
|
|
49
|
+
* rewritten) args and has the final say ({@link runToolGate}).
|
|
311
50
|
*/
|
|
312
|
-
export
|
|
51
|
+
export interface PreToolUseEvent extends ClassicEventBase {
|
|
52
|
+
/** The call's wire name (the tool the call dispatches to). */
|
|
53
|
+
readonly tool: string;
|
|
54
|
+
readonly tool_use_id: string;
|
|
55
|
+
/** A deep-frozen copy of the args the gate judges. */
|
|
56
|
+
readonly input: unknown;
|
|
57
|
+
/** The TASK's tracked working directory at this call — the base the hand tools resolve a RELATIVE path against,
|
|
58
|
+
* read live off the same ref the tool policy reads. NOT {@link HookEnvCapabilities.cwd} (the environment's own,
|
|
59
|
+
* which never moves on a shell `cd` or a worktree entry). ABSENT when the run has no tracked cwd to report (no real
|
|
60
|
+
* write hands, a host-driven gate without one, the delegation-fold twin) — absence means "this engine cannot tell
|
|
61
|
+
* you", never "the root". */
|
|
62
|
+
readonly cwd?: string;
|
|
63
|
+
/** The read-only path-resolution face over the env the hands run against ({@link HookEnvCapabilities}). ABSENT when
|
|
64
|
+
* the deployment wired no execution environment at all. */
|
|
65
|
+
readonly env?: HookEnvCapabilities;
|
|
66
|
+
}
|
|
67
|
+
/** `classic.PostToolUse`'s `e` — after a tool executed successfully. Answer: {@link PostToolUseResult}. */
|
|
68
|
+
export interface PostToolUseEvent extends ClassicEventBase {
|
|
69
|
+
readonly tool: string;
|
|
70
|
+
readonly tool_use_id: string;
|
|
71
|
+
readonly input: unknown;
|
|
72
|
+
readonly output: HookToolOutput;
|
|
73
|
+
readonly cwd?: string;
|
|
74
|
+
readonly env?: HookEnvCapabilities;
|
|
75
|
+
}
|
|
313
76
|
/**
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
* `owner` is the record the value was read off; passing it bounds the disclosure to once per record
|
|
319
|
-
* (see {@link badHookTimeoutReported}). Omit it where the caller already bounds its own channel.
|
|
77
|
+
* `classic.PostToolUseFailure`'s `e` — after a tool EXECUTION failed (mutually exclusive with `classic.PostToolUse`).
|
|
78
|
+
* Raised ONLY for genuine execution failures: a gate/policy block, a plan-mode deny, a pre-execution abort or a durable
|
|
79
|
+
* suspend raises neither post event. Answer: {@link PostToolUseFailureResult} (context only; the failure itself cannot
|
|
80
|
+
* be rewritten).
|
|
320
81
|
*/
|
|
321
|
-
export
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
/** What one bounded seat invocation produced: the seat's own value, or the fact that the wait ended
|
|
329
|
-
* first. A seat that THREW is neither — the throw propagates out of {@link runHookSeat} unchanged, so
|
|
330
|
-
* each site's existing crash arm keeps owning it. */
|
|
331
|
-
export type HookSeatOutcome<T> = {
|
|
332
|
-
readonly expired: false;
|
|
333
|
-
readonly value: T;
|
|
334
|
-
} | {
|
|
335
|
-
readonly expired: true;
|
|
336
|
-
readonly cause: "timeout" | "aborted";
|
|
337
|
-
};
|
|
338
|
-
/** How one seat invocation is bounded. */
|
|
339
|
-
export interface HookSeatBound {
|
|
340
|
-
/** The deployment's declared bound ({@link Hooks.timeoutMs}); re-validated here, so a caller that
|
|
341
|
-
* already validated pays nothing and a caller that did not cannot pass garbage through. */
|
|
342
|
-
timeoutMs?: number;
|
|
343
|
-
/** The task abort signal. It is ALWAYS forwarded to the seat (so an implementation can cancel its own
|
|
344
|
-
* underlying wait) and it ALWAYS shortens the wait — the two seat kinds differ only in HOW MUCH.
|
|
345
|
-
* Supply it wherever the caller has one: a seat with no signal is bounded by its deadline alone, and
|
|
346
|
-
* a ten-minute default deadline is not a cancellation story. */
|
|
347
|
-
signal?: AbortSignal;
|
|
348
|
-
/** True for a seat whose answer is MOOT once the task is ending — the DECISION seats. Those settle as
|
|
349
|
-
* `aborted` the instant the task is cancelled. An observation seat leaves this false on purpose:
|
|
350
|
-
* `postToolUseFailure` fires precisely BECAUSE the task aborted (`isInterrupt`), and cancelling it
|
|
351
|
-
* outright would delete the observation the seat exists to deliver — it gets
|
|
352
|
-
* {@link POST_ABORT_GRACE_MS} instead of the full deadline. */
|
|
353
|
-
abortEnds?: boolean;
|
|
354
|
-
/** Where a bad {@link timeoutMs} is disclosed. The EXPIRY itself is not reported here — each site
|
|
355
|
-
* words its own, because the sentence a deployment needs includes what the engine then did. */
|
|
356
|
-
onBadTimeout?: (err: unknown) => void;
|
|
357
|
-
/** The hook record the bound was read off, for once-per-record bad-value disclosure. */
|
|
358
|
-
owner?: object;
|
|
82
|
+
export interface PostToolUseFailureEvent extends ClassicEventBase {
|
|
83
|
+
readonly tool: string;
|
|
84
|
+
readonly tool_use_id: string;
|
|
85
|
+
readonly input: unknown;
|
|
86
|
+
readonly failure: HookToolFailure;
|
|
87
|
+
readonly cwd?: string;
|
|
88
|
+
readonly env?: HookEnvCapabilities;
|
|
359
89
|
}
|
|
360
90
|
/**
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
* callback that reads its own mutable state before its first `await` must see the turn it always saw;
|
|
367
|
-
* · a SYNCHRONOUS throw propagates unchanged (it never reached a deadline, and the site's crash arm is
|
|
368
|
-
* the contract for it), and so does an asynchronous rejection;
|
|
369
|
-
* · the seat's signal fires when — and ONLY when — this function stops waiting, and its promise is then
|
|
370
|
-
* abandoned with a rejection sink attached (an abandoned seat that fails later must not surface as an
|
|
371
|
-
* unhandled rejection somewhere else). The task's own signal is never forwarded raw: for an
|
|
372
|
-
* OBSERVATION seat the task being cancelled is not a reason to stop, it is the reason the seat is
|
|
373
|
-
* firing at all;
|
|
374
|
-
* · the TASK signal ends the wait on both kinds of seat, differently. A DECISION seat
|
|
375
|
-
* ({@link HookSeatBound.abortEnds}) settles as `aborted` the moment the task is cancelled, INCLUDING
|
|
376
|
-
* when it was already cancelled on entry — a verdict about a call that will not run decides nothing,
|
|
377
|
-
* and waiting the full deadline for one holds a cancelled task open for as long as the deadline says.
|
|
378
|
-
* On the entry case the callback is still INVOKED (an audit face keeps seeing the attempt) and its
|
|
379
|
-
* answer is discarded: settling on the cancellation rather than on whichever of the two happened to
|
|
380
|
-
* land first is what makes the arm a rule instead of a race.
|
|
381
|
-
* An OBSERVATION seat is not cancelled by the abort — it fires precisely BECAUSE the task aborted
|
|
382
|
-
* (`isInterrupt`), and racing it against that same abort would delete the observation it exists to
|
|
383
|
-
* deliver — but it does not get the full deadline either: the abort collapses its wait to
|
|
384
|
-
* {@link POST_ABORT_GRACE_MS}. Prompt observers still land; a hung one can no longer hold a cancelled
|
|
385
|
-
* task's settlement for the length of the whole bound.
|
|
91
|
+
* `classic.PostToolBatch`'s `e` — raised ONCE after every tool call of one assistant turn resolved, before the next
|
|
92
|
+
* model request (the per-call post events fire first). A zero-tool turn, an aborted or steered-away boundary raise
|
|
93
|
+
* nothing. On a boundary where the engine itself injected (`injectedThisTurn`) the batch is DELIVERED with that
|
|
94
|
+
* attribution and the answer's `additionalContext` is IGNORED (no stacking onto an engine injection). Answer:
|
|
95
|
+
* {@link PostToolBatchResult}.
|
|
386
96
|
*/
|
|
387
|
-
export
|
|
97
|
+
export interface PostToolBatchEvent extends ClassicEventBase {
|
|
98
|
+
readonly batch: readonly PostToolBatchCall[];
|
|
99
|
+
readonly injectedThisTurn?: "final_verification" | "finalize";
|
|
100
|
+
}
|
|
388
101
|
/**
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
*
|
|
102
|
+
* `classic.UserPromptSubmit`'s `e` — EVERY user-lane entrance: the objective, a live steer, a wake resume's message
|
|
103
|
+
* (pre-claim, at the verb) and a parked steer's redelivery, discriminated by {@link source}. Pinned: `source`,
|
|
104
|
+
* `inputId`, `actor`. A handler that blocks unconditionally therefore refuses steers too — branch on `source` (and
|
|
105
|
+
* `actor`). Answer: {@link UserPromptSubmitResult}. Block per entrance: objective ⇒ the task ends `blocked`; live steer
|
|
106
|
+
* ⇒ typed `steering.blocked_by_hook`; resume message ⇒ typed pre-claim refusal (the checkpoint stays pending); parked
|
|
107
|
+
* redelivery ⇒ the frame is withheld (a `steering.parked_input_blocked` notice) and the resume proceeds.
|
|
392
108
|
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
* says nothing about the hook at all — and one sentence covering both would have to be false about one
|
|
396
|
-
* of them. (It was: the first version of this said "did not answer within its Nms bound" on every
|
|
397
|
-
* expiry, including the ones where the bound was never reached.)
|
|
109
|
+
* ⚠️ RE-ENTRANT within one leg: the steer verb goes live before the objective screen runs, so screens can overlap in
|
|
110
|
+
* flight; only steer-vs-steer is serialized (FIFO — each queued steer waits behind its predecessor's whole screen).
|
|
398
111
|
*/
|
|
399
|
-
export
|
|
400
|
-
/** The
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
*
|
|
404
|
-
*
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
toolCallId: string;
|
|
411
|
-
/** Human/model-readable deny reason (CC `reason`) — the RAW decision text, NOT `<system-reminder>`-wrapped. */
|
|
412
|
-
reason: string;
|
|
112
|
+
export interface UserPromptSubmitEvent extends ClassicEventBase {
|
|
113
|
+
/** The caller's text, raw. */
|
|
114
|
+
readonly prompt: string;
|
|
115
|
+
/**
|
|
116
|
+
* WHICH entrance: `"objective"` (the task's opening prompt), `"steer"` (a live mid-run steer), `"resume_message"`
|
|
117
|
+
* (a wake resume's message, screened pre-claim), `"parked_redelivery"` (a parked steer re-screened on the CURRENT
|
|
118
|
+
* process when any resume kind that drains parked steers redelivers it). ⚠️ DOUBLE ARRIVAL IS CONTRACTUAL: one input
|
|
119
|
+
* can arrive twice (screened live as `"steer"`, parked, re-screened as `"parked_redelivery"`) — idempotency is the
|
|
120
|
+
* handler's, keyed on {@link inputId}. `"followUp"` is a RESERVED spelling: no entrance carries it yet.
|
|
121
|
+
*/
|
|
122
|
+
readonly source: "objective" | "steer" | "resume_message" | "followUp" | "parked_redelivery";
|
|
413
123
|
/**
|
|
414
|
-
* The
|
|
415
|
-
* the
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
* an absence: a direct policy / hook / plan-mode / compliance deny carries no settlement because it
|
|
419
|
-
* settled none.
|
|
124
|
+
* The screened input's correlation id — present on every entrance but the objective (no id exists there; nothing is
|
|
125
|
+
* fabricated): the steer's effective id, the parked entry's stored id, or the wake message's id (the caller's, else
|
|
126
|
+
* minted PER CALL — a retried wake with no caller id re-screens under a fresh id; a host that retries wakes mints its
|
|
127
|
+
* own). The dedup key for the double-arrival contract.
|
|
420
128
|
*/
|
|
421
|
-
|
|
422
|
-
/**
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
*
|
|
427
|
-
|
|
129
|
+
readonly inputId?: string;
|
|
130
|
+
/** The API-boundary actor snapshot attributed to this input (the one the `human_input` event reports), when the caller
|
|
131
|
+
* supplied one. Attribution only, never authority. */
|
|
132
|
+
readonly actor?: ActorAssertion;
|
|
133
|
+
/**
|
|
134
|
+
* The files declared on this objective (`TaskSpec.userAttachments`), in order — present only on `source:"objective"`
|
|
135
|
+
* when the objective declares any. A path entry shows its path; a host entry its name and byte count, never its
|
|
136
|
+
* bytes. Blocking the objective reads and delivers none of them. A handler does not govern the engine's reading of an
|
|
137
|
+
* allowed attachment (`classic.PreToolUse` is not raised for it either): a deployment that must keep a path from the
|
|
138
|
+
* model writes a deny rule, which the attachment read honors like the Read tool does.
|
|
139
|
+
*/
|
|
140
|
+
readonly userAttachments?: readonly import("./user-attachment.js").UserAttachmentDeclaration[];
|
|
428
141
|
}
|
|
429
|
-
/**
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
/**
|
|
437
|
-
*
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
|
|
142
|
+
/**
|
|
143
|
+
* `classic.Stop`'s `e` — raised when the agent WOULD OTHERWISE END its run (no more tool calls, steering and follow-up
|
|
144
|
+
* queues dry). Answer: {@link StopHookResult}; `{ block }` pushes back (the reason is injected and the run continues one
|
|
145
|
+
* more turn). Guardrails (CC-exact): consecutive push-backs are capped (default 8 — the loop then overrides and ends with
|
|
146
|
+
* a warning); `stopHookActive` is true while the run is already continuing because of one. `maxTurns` outranks it.
|
|
147
|
+
*/
|
|
148
|
+
export interface StopEvent extends ClassicEventBase {
|
|
149
|
+
/** True when this run is already continuing because a previous answer pushed back — check it and let the run end
|
|
150
|
+
* once your condition can't be improved, or it loops to the cap. */
|
|
151
|
+
readonly stopHookActive: boolean;
|
|
152
|
+
/** Consecutive push-backs so far in this run (resets when the run is let proceed). */
|
|
153
|
+
readonly consecutiveBlocks: number;
|
|
154
|
+
/** A LAZY view of the conversation being judged (a handler that only reads the counters pays nothing). Absent when
|
|
155
|
+
* the runner cannot supply one. */
|
|
156
|
+
readonly getBranch?: () => Promise<readonly SessionTreeEntry[]>;
|
|
157
|
+
/** The run's background tasks still in flight (pending / running / parked under this run's owner triple; CC
|
|
158
|
+
* `SubagentStop.background_tasks`). LAZY like {@link getBranch}; `[]` = none, ABSENT = no view. */
|
|
159
|
+
readonly backgroundTasks?: () => ReadonlyArray<{
|
|
160
|
+
id: string;
|
|
161
|
+
description?: string;
|
|
162
|
+
status: string;
|
|
163
|
+
}>;
|
|
443
164
|
}
|
|
444
165
|
/**
|
|
445
|
-
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
* It carries exactly one meaning: **the engine has stopped waiting for this invocation.** It is not the
|
|
449
|
-
* task's abort signal and it never fires early on the task's behalf — a DECISION seat's wait ends when
|
|
450
|
-
* the task is cancelled, so its signal fires then; an OBSERVATION seat's wait ends at its deadline or
|
|
451
|
-
* after the post-abort grace, so its signal fires there and NOT at the cancellation itself. The
|
|
452
|
-
* difference is deliberate: a `postToolUseFailure` fires precisely BECAUSE the task aborted, and a
|
|
453
|
-
* signal that went off at the cancellation would tell a cooperative observer to abandon the very
|
|
454
|
-
* observation it was invoked to deliver.
|
|
455
|
-
*
|
|
456
|
-
* Honoring it is optional and it changes nothing about the engine's own behavior — the engine stops
|
|
457
|
-
* waiting either way. What it is for is the deployment's side of that: a seat that was awaiting a
|
|
458
|
-
* network read, a lock or a subprocess can cancel it instead of leaving an orphan running with nobody
|
|
459
|
-
* left to read its answer. Absent when a host drives a seat outside the engine's own invocation (no
|
|
460
|
-
* bound, nothing to signal).
|
|
166
|
+
* `classic.StopFailure`'s `e` — raised ONCE, after the result is assembled, when the task terminates `failed` BECAUSE
|
|
167
|
+
* the model/API layer errored. NOT for engine-owned failure classes (budget, timeout/abort, max-turns, degenerate /
|
|
168
|
+
* walltime cutoffs, storage conflict, blocked, a durable suspend). Observe-only.
|
|
461
169
|
*/
|
|
462
|
-
export
|
|
170
|
+
export interface StopFailureEvent extends ClassicEventBase {
|
|
171
|
+
/** Human-readable error message (the assembled `errorMessage`; any `[code]` prefix already stripped). */
|
|
172
|
+
readonly error: string;
|
|
173
|
+
/** Machine-readable kind — the assembled `errorCode` (auth / network / rate_limit / server_error / …); absent when
|
|
174
|
+
* the provider stamped no code. */
|
|
175
|
+
readonly errorKind?: string;
|
|
176
|
+
/** Turns completed when the failure ended the run. */
|
|
177
|
+
readonly turns: number;
|
|
178
|
+
}
|
|
179
|
+
/** `classic.PreCompact`'s `e` — before each compaction, after the trigger gate and a valid cut point. Answer:
|
|
180
|
+
* {@link PreCompactResult} (`block` honored on "auto" / "manual" only). */
|
|
181
|
+
export interface PreCompactEvent extends ClassicEventBase {
|
|
182
|
+
readonly trigger: PreCompactContext["trigger"];
|
|
183
|
+
readonly customInstructions?: string;
|
|
184
|
+
}
|
|
185
|
+
/** `classic.PostCompact`'s `e` — observe-only, after the compaction landed. */
|
|
186
|
+
export interface PostCompactEvent extends ClassicEventBase {
|
|
187
|
+
readonly trigger: PostCompactContext["trigger"];
|
|
188
|
+
readonly summary: string;
|
|
189
|
+
readonly tokensBefore?: number;
|
|
190
|
+
readonly tokensAfter?: number;
|
|
191
|
+
readonly freedTokens?: number;
|
|
192
|
+
}
|
|
193
|
+
/** `classic.PermissionDenied`'s `e` (CC-exact fields + the gate outcome) — raised when the gate's adjudicate chain
|
|
194
|
+
* DENY-SHORT-CIRCUITS a call (a policy deny, a tighten whose ask resolved to deny, the plan-mode write-deny, the
|
|
195
|
+
* compliance deny) and on the engine's fail-closed refusal of a failed PreToolUse screening (`source:"hook"`); NOT on a
|
|
196
|
+
* PreToolUse handler's own deny (that is the handler's decision, and this event attributes the ENGINE's) nor on a
|
|
197
|
+
* durable suspend. Observe-only. `identity` is present on every ENGINE emission; absent only when a host drives
|
|
198
|
+
* {@link runToolGate} without `ToolGateInput.identity`. (CC raises its PermissionDenied from the auto-mode classifier's
|
|
199
|
+
* refusals alone; sema's trigger surface is deliberately WIDER — a divergence, not a parity claim.) */
|
|
200
|
+
export interface PermissionDeniedPayload extends ClassicEventBase {
|
|
201
|
+
readonly toolName: string;
|
|
202
|
+
/** The FINAL (post-rewrite) args the chain adjudicated — what would have executed; not necessarily the model's
|
|
203
|
+
* original args. A detached copy (the live args are shared with later frames and audit records). */
|
|
204
|
+
readonly input: unknown;
|
|
205
|
+
readonly toolCallId: string;
|
|
206
|
+
/** Human/model-readable deny reason (CC `reason`) — the RAW decision text, NOT `<system-reminder>`-wrapped. */
|
|
207
|
+
readonly reason: string;
|
|
208
|
+
/**
|
|
209
|
+
* The gate outcome this deny is — the SAME object the call's `tool_end` frame carries as `gate` and the engine's
|
|
210
|
+
* per-call sideband records (one mint, three faces). `disposition.deniedBy` says which LAYER refused; when the
|
|
211
|
+
* refusal came through an ask resolution, `settlement` says how the wait ended and `origin` who asked.
|
|
212
|
+
*/
|
|
213
|
+
readonly gate: GateOutcome;
|
|
214
|
+
}
|
|
463
215
|
/** The failed tool execution a PostToolUseFailure callback inspects (design/134). */
|
|
464
216
|
export interface HookToolFailure {
|
|
465
217
|
/** Model-facing error text of the failed call (the error tool result's text content, joined). */
|
|
@@ -497,19 +249,13 @@ export interface PostToolBatchCall {
|
|
|
497
249
|
export interface PostToolBatchResult {
|
|
498
250
|
additionalContext?: string;
|
|
499
251
|
}
|
|
500
|
-
/**
|
|
252
|
+
/** What the compaction module hands its `preCompact` option (design/134); the Runner raises `classic.PreCompact` from it. */
|
|
501
253
|
export interface PreCompactContext {
|
|
502
|
-
/** #281 件A — the run/leg identity envelope. Present when the Runner drives the compaction (its
|
|
503
|
-
* wrapper injects it); honestly absent when a deployment drives the compaction module directly
|
|
504
|
-
* (presence law arm 3 on {@link HookInvocationIdentity}). */
|
|
505
|
-
identity?: HookInvocationIdentity;
|
|
506
254
|
/** "auto" = threshold-triggered; "manual" = /compact; "forced" = promptTooLong recovery or
|
|
507
255
|
* trim-pressure propagation (block is ignored on forced — the compaction is not optional). */
|
|
508
256
|
trigger: "auto" | "manual" | "forced";
|
|
509
257
|
/** The summarization instructions in effect (spec/deployment-level), when set. */
|
|
510
258
|
customInstructions?: string;
|
|
511
|
-
/** {@link HookSeatSignal} — this invocation's own abort signal. */
|
|
512
|
-
signal?: AbortSignal;
|
|
513
259
|
}
|
|
514
260
|
/** A PreCompact result: skip this compaction (auto/manual only) and/or extend the summary instructions. */
|
|
515
261
|
export interface PreCompactResult {
|
|
@@ -521,10 +267,8 @@ export interface PreCompactResult {
|
|
|
521
267
|
* extending the provider contract is out of scope for design/134). */
|
|
522
268
|
additionalInstructions?: string;
|
|
523
269
|
}
|
|
524
|
-
/**
|
|
270
|
+
/** What the compaction module hands its `postCompact` option (design/134, observe-only); the Runner raises `classic.PostCompact` from it. */
|
|
525
271
|
export interface PostCompactContext {
|
|
526
|
-
/** #281 件A — same presence law as {@link PreCompactContext.identity}. */
|
|
527
|
-
identity?: HookInvocationIdentity;
|
|
528
272
|
trigger: "auto" | "manual" | "forced";
|
|
529
273
|
/** The conversation summary the compaction produced (CC `compact_summary` parity). */
|
|
530
274
|
summary: string;
|
|
@@ -537,45 +281,6 @@ export interface PostCompactContext {
|
|
|
537
281
|
/** The engine's measured delta (clamped ≥ 0) — the ONE subtractable number here, and the same value
|
|
538
282
|
* this pass's `compacted` frame carries. Absent ⇒ the post measurement failed. */
|
|
539
283
|
freedTokens?: number;
|
|
540
|
-
/** {@link HookSeatSignal} — this invocation's own abort signal. */
|
|
541
|
-
signal?: AbortSignal;
|
|
542
|
-
}
|
|
543
|
-
/** Context for the {@link Hooks.stop} hook (CC `stop_hook_active` parity). */
|
|
544
|
-
export interface StopHookContext {
|
|
545
|
-
/** #281 件A — the run/leg identity envelope. The load-bearing member for THIS seat: a process-level
|
|
546
|
-
* `deps.hooks.stop` fires in root, delegated-child and resume legs alike, and previously could not
|
|
547
|
-
* tell which run it was being asked to end (matrix row 10/13 residual). Always present on the
|
|
548
|
-
* engine's stop-gate emission. */
|
|
549
|
-
identity?: HookInvocationIdentity;
|
|
550
|
-
/** True when this run is already continuing because a previous stop() blocked — check it and
|
|
551
|
-
* return success (undefined) once your condition can't be improved, or you will loop to the cap. */
|
|
552
|
-
stopHookActive: boolean;
|
|
553
|
-
/** Consecutive blocks so far in this run (resets when a stop() call lets the run proceed). */
|
|
554
|
-
consecutiveBlocks: number;
|
|
555
|
-
/**
|
|
556
|
-
* A view of the conversation this hook is being asked to judge — the counters alone cannot serve a
|
|
557
|
-
* hook that asks anything ABOUT THE RUN (the prompt-shaped hooks a settings file declares).
|
|
558
|
-
*
|
|
559
|
-
* LAZY on purpose: a hook that only reads the counters pays nothing, and a hook that needs the
|
|
560
|
-
* conversation gets it in full rather than through a truncation policy the engine would have to invent
|
|
561
|
-
* on its behalf. Callers decide what to send to a model and how much — that decision has a budget and a
|
|
562
|
-
* trust tier attached, and both belong to the caller.
|
|
563
|
-
*
|
|
564
|
-
* Absent when the runner cannot supply one (a stop gate wired without a session).
|
|
565
|
-
*/
|
|
566
|
-
getBranch?: () => Promise<readonly SessionTreeEntry[]>;
|
|
567
|
-
/** The run's background tasks still in flight (pending / running / parked under this run's owner triple — the
|
|
568
|
-
* post-compaction reminder's projection; CC `SubagentStop.background_tasks`). LAZY like {@link getBranch};
|
|
569
|
-
* `[]` = none in that projection, ABSENT = no view. A parked child here waits on an approval out of band. */
|
|
570
|
-
backgroundTasks?: () => ReadonlyArray<{
|
|
571
|
-
id: string;
|
|
572
|
-
description?: string;
|
|
573
|
-
status: string;
|
|
574
|
-
}>;
|
|
575
|
-
/** {@link HookToolContext.permissionMode}. */
|
|
576
|
-
permissionMode?: PermissionMode;
|
|
577
|
-
/** {@link HookSeatSignal} — this invocation's own abort signal. */
|
|
578
|
-
signal?: AbortSignal;
|
|
579
284
|
}
|
|
580
285
|
/** A Stop hook result: block the run from ending, with a model-readable reason. */
|
|
581
286
|
export interface StopHookResult {
|
|
@@ -602,7 +307,7 @@ export interface StopHookResult {
|
|
|
602
307
|
}
|
|
603
308
|
/**
|
|
604
309
|
* A READ-ONLY path-resolution capability face over the task's {@link ExecutionEnv}, handed to tool hooks
|
|
605
|
-
* on {@link
|
|
310
|
+
* on {@link PreToolUseEvent.env} (and the two post events' `env`).
|
|
606
311
|
*
|
|
607
312
|
* **Why it exists.** A hook that judges a path — "is this write inside the workspace", "does this
|
|
608
313
|
* innocent-looking name resolve onto a guarded file" — must resolve it in the filesystem the HANDS
|
|
@@ -613,7 +318,7 @@ export interface StopHookResult {
|
|
|
613
318
|
* env off the CALL CONTEXT removes the ordering problem structurally: the context is built after the env
|
|
614
319
|
* is, and a resumed/revived run's rebuilt env is picked up with no re-instantiation protocol.
|
|
615
320
|
*
|
|
616
|
-
* **Capabilities, not the object.**
|
|
321
|
+
* **Capabilities, not the object.** A classic handler is an extension boundary the deployment fills with code whose
|
|
617
322
|
* job is to DECIDE; the whole `ExecutionEnv` is a face that can ACT (`exec`, `writeFile`, `remove`,
|
|
618
323
|
* `cleanup`). So this is four INDEPENDENTLY BOUND read primitives and nothing else: no `env`
|
|
619
324
|
* back-reference, no prototype of the env object, and the face itself is frozen (a hook cannot re-point a
|
|
@@ -687,38 +392,26 @@ export interface HookEnvCapabilities {
|
|
|
687
392
|
*/
|
|
688
393
|
export declare function createHookEnvCapabilities(env: ExecutionEnv): HookEnvCapabilities;
|
|
689
394
|
/**
|
|
690
|
-
*
|
|
691
|
-
*
|
|
692
|
-
*
|
|
693
|
-
* (session/leg/delegation axes), not a transcription of CC's field names.
|
|
395
|
+
* The UNIFIED IDENTITY ENVELOPE every classic event can carry (`e.identity`): which run, which leg, and
|
|
396
|
+
* where in the delegation tree the event is raised. The CC analog is `createBaseHookInput`'s per-event base fields;
|
|
397
|
+
* the members here are sema's OWN identity facts (session/leg/delegation axes), not a transcription of CC's names.
|
|
694
398
|
*
|
|
695
|
-
* WHY: `
|
|
696
|
-
*
|
|
697
|
-
*
|
|
698
|
-
* `identity?: HookInvocationIdentity`, so a consumer that never reads it sees nothing new.
|
|
399
|
+
* WHY: the deployment seat (`RunnerDeps.mods`) is PROCESS-level — one handler serves the root run, every delegated
|
|
400
|
+
* child and every resume leg at once, and without this envelope none of those events could say which leg it belongs
|
|
401
|
+
* to (`e.agentId` names a delegated leg on every event too).
|
|
699
402
|
*
|
|
700
|
-
* PRESENCE LAW
|
|
701
|
-
* · PRESENT on every ENGINE-
|
|
702
|
-
*
|
|
703
|
-
*
|
|
704
|
-
*
|
|
705
|
-
*
|
|
706
|
-
*
|
|
707
|
-
* · HONESTLY ABSENT (no fabrication)
|
|
708
|
-
* 1. a HOST driving the exported {@link runToolGate} directly without supplying
|
|
709
|
-
*
|
|
710
|
-
*
|
|
711
|
-
*
|
|
712
|
-
* request shape carries no leg identity, and stamping the INSTALL-site leg would name the
|
|
713
|
-
* wrong run;
|
|
714
|
-
* 3. a deployment driving the compaction module directly with its own `preCompact`/`postCompact`
|
|
715
|
-
* options — those contexts are built below the runner, which is where the envelope lives;
|
|
716
|
-
* 4. the PRE-CAS durable-resume observation of a declared-observational PreToolUse face
|
|
717
|
-
* (resumeStream's edited-args leg) — it runs BEFORE the resume leg prepares, so the leg's
|
|
718
|
-
* envelope does not exist yet, and minting a partial one off the checkpoint would guess at
|
|
719
|
-
* the delegation axes (the row persists `isDelegatedChild` alone; `insideFork`/`agentName`/
|
|
720
|
-
* `parentToolCallId` are internals-only, and a wrong guess is worse than an honest
|
|
721
|
-
* absence). The SAME face is re-consulted with full identity by the resumed leg's own gate.
|
|
403
|
+
* PRESENCE LAW:
|
|
404
|
+
* · PRESENT on every ENGINE-raised classic event: the gate's `classic.PreToolUse` screenings (phase 1, the
|
|
405
|
+
* approval-edit re-screen, the resumed leg's re-screen), the two post events, `classic.PostToolBatch`, every
|
|
406
|
+
* `classic.UserPromptSubmit` entrance (the resume-message screen carries the pre-leg envelope minted off the
|
|
407
|
+
* checkpoint and the trusted spawn facts), `classic.Stop`, `classic.StopFailure`, the compaction pair, and every
|
|
408
|
+
* engine `classic.PermissionDenied`. The engine mints ONE frozen envelope per prepared leg
|
|
409
|
+
* ({@link mintHookInvocationIdentity} — single mint home) and every station reuses it.
|
|
410
|
+
* · HONESTLY ABSENT (no fabrication) where the engine structurally cannot know:
|
|
411
|
+
* 1. a HOST driving the exported {@link runToolGate} directly without supplying `ToolGateInput.identity`;
|
|
412
|
+
* 2. an ancestor's chain riding a DESCENDANT's constraint fold ({@link createPreToolUseConstraintPolicy}) — the
|
|
413
|
+
* fold's request carries no leg identity, and stamping the INSTALL-site leg would name the wrong run;
|
|
414
|
+
* 3. a deployment driving the compaction module directly with its own `preCompact`/`postCompact` options.
|
|
722
415
|
*
|
|
723
416
|
* CONSUMER NOTE — the minted object is FROZEN and carries a NULL PROTOTYPE (same rule and same
|
|
724
417
|
* trade as {@link HookEnvCapabilities}: absence must be a fact about this object, not about what
|
|
@@ -776,55 +469,6 @@ export interface HookInvocationIdentity {
|
|
|
776
469
|
* is the only member whose value a model influences.
|
|
777
470
|
*/
|
|
778
471
|
export declare function mintHookInvocationIdentity(facts: HookInvocationIdentity): HookInvocationIdentity;
|
|
779
|
-
/** Identifying context passed to tool hooks. */
|
|
780
|
-
export interface HookToolContext {
|
|
781
|
-
toolCallId: string;
|
|
782
|
-
toolName: string;
|
|
783
|
-
/** #281 件A — the run/leg identity envelope; see {@link HookInvocationIdentity} for the presence
|
|
784
|
-
* law (present on engine-driven gates; absent on a host-driven gate without
|
|
785
|
-
* `ToolGateInput.identity` and on the delegation-fold twin). */
|
|
786
|
-
identity?: HookInvocationIdentity;
|
|
787
|
-
/**
|
|
788
|
-
* The read-only path-resolution face over the env the hands run against (see
|
|
789
|
-
* {@link HookEnvCapabilities} for the why, and for why it is capabilities rather than the env object).
|
|
790
|
-
*
|
|
791
|
-
* ABSENT when the deployment wired no execution environment at all (no `executionEnv` /
|
|
792
|
-
* `executionEnvFactory`: the run has no hands, and the engine's internal no-I/O placeholder is not an
|
|
793
|
-
* environment to report). Present ⇒ inspect the individual members: each one is itself optional.
|
|
794
|
-
*/
|
|
795
|
-
env?: HookEnvCapabilities;
|
|
796
|
-
/**
|
|
797
|
-
* The TASK's tracked working directory at this call — the base the hand tools will resolve a RELATIVE
|
|
798
|
-
* path against, read live off the same ref the tool policy reads (so a hook and a policy judging the
|
|
799
|
-
* same call judge it against the same base).
|
|
800
|
-
*
|
|
801
|
-
* It is NOT {@link HookEnvCapabilities.cwd}, and the difference is the reason this member exists: that
|
|
802
|
-
* one is the ENVIRONMENT's own working directory, which never moves when the shell `cd`s or the run
|
|
803
|
-
* enters a worktree. A hook is documented — on the capability face itself — as the seat that judges
|
|
804
|
-
* "is this write inside the workspace", and it was the only seat in the gate that could not resolve a
|
|
805
|
-
* relative target the way the tool would. CC ships its own `cwd` to every hook event for the same
|
|
806
|
-
* reason; this is that field, named for the value it actually carries.
|
|
807
|
-
*
|
|
808
|
-
* ABSENT when the run has no tracked cwd to report — no real write hands (read-only or no shell), a
|
|
809
|
-
* host driving {@link runToolGate} without one, or the delegation-fold twin (which runs inside a
|
|
810
|
-
* DESCENDANT's policy fold and would otherwise report the install site's directory, i.e. the wrong
|
|
811
|
-
* machine's answer). Absence means "this engine cannot tell you", never "the root".
|
|
812
|
-
*/
|
|
813
|
-
cwd?: string;
|
|
814
|
-
/** The leg's EFFECTIVE permission mode when the callback is invoked — the mode seat's `observed` read (it arms
|
|
815
|
-
* no classifier on the leg or an ancestor, so it moves no decision); a steer, a plan-mode entry or exit and a
|
|
816
|
-
* resumed leg's restored word show on the next callback. Stamped by the Runner on its own legs' contexts (this
|
|
817
|
-
* one, {@link PermissionDeniedPayload}, {@link UserPromptSubmitContext}, {@link PostToolBatchContext},
|
|
818
|
-
* {@link StopHookContext}); ABSENT ⇔ no leg seat: a host-driven {@link runToolGate} (its
|
|
819
|
-
* `ToolGateInput.permissionMode` is the arbitration's reader, never called for this), the delegation-fold twin,
|
|
820
|
-
* the `"resume_message"` screen (before the resumed leg exists). Not a version signal. The compaction seats and
|
|
821
|
-
* {@link StopFailureContext} carry none (the reference's hook input omits it there). */
|
|
822
|
-
permissionMode?: PermissionMode;
|
|
823
|
-
/** {@link HookSeatSignal} — this invocation's own abort signal. A FRESH one per screening pass, like
|
|
824
|
-
* the context object it rides: phase 1 and the approval-edit re-screen are two bounded waits, and a
|
|
825
|
-
* shared signal would let the first pass's expiry cancel the second. */
|
|
826
|
-
signal?: AbortSignal;
|
|
827
|
-
}
|
|
828
472
|
/** The executed tool result a PostToolUse hook inspects. */
|
|
829
473
|
export interface HookToolOutput {
|
|
830
474
|
content: Array<TextContent | ImageContent | DocumentContent>;
|
|
@@ -861,7 +505,7 @@ export interface HookToolOutput {
|
|
|
861
505
|
* {@link createPreToolUseConstraintPolicy} speaks the same words as a policy layer). "Held" = the ask survives to a person:
|
|
862
506
|
* neither an allow rule (`decisionReason: "hook"` is outside the allow layer) nor the classifier (hook asks are
|
|
863
507
|
* never classifier-answerable) clears it.
|
|
864
|
-
* · returns `allow` (± `updatedInput` / `additionalContext`) → the face's own word (`
|
|
508
|
+
* · returns `allow` (± `updatedInput` / `additionalContext`) → the face's own word (`hookAllowedBy`, naming the registration); the policy
|
|
865
509
|
* still adjudicates the FINAL args; the allow layer's hook member may clear an unmandated ask. Not held.
|
|
866
510
|
* · returns `ask` (± `updatedInput`, ± `requiresRealApproval`) → folded as `hookAsk`: a policy deny still
|
|
867
511
|
* outranks it, a policy allow is PROMOTED to this ask with `"hook"` stamped by the engine; the rewrite rides
|
|
@@ -869,10 +513,10 @@ export interface HookToolOutput {
|
|
|
869
513
|
* · returns `deny` → {@link hookDenyExit}: the hook's OWN refusal — the deny observer does NOT fire, the model
|
|
870
514
|
* reads the hook's sentence. Nothing executes.
|
|
871
515
|
* · returns `undefined` ("no opinion") or no screening face is installed → no word at all; the policy decides.
|
|
872
|
-
* · throws /
|
|
873
|
-
* {@link
|
|
874
|
-
* `
|
|
875
|
-
* executes, nothing is held.
|
|
516
|
+
* · a handler throws / runs past its budget / breaks the site's contract (an out-of-contract answer, refused by
|
|
517
|
+
* {@link screenPreToolUseResult}), or the dispatch is aborted → {@link engineFailClosedExit}: an ENGINE deny — the
|
|
518
|
+
* deny observer fires, a crash and a timeout also reach `onError(phase:"hook")` (an abort does not), the model reads
|
|
519
|
+
* the engine's envelope. Nothing executes, nothing is held.
|
|
876
520
|
*/
|
|
877
521
|
export type PreToolUseResult = PermissionResult & {
|
|
878
522
|
additionalContext?: string;
|
|
@@ -884,80 +528,6 @@ export interface PostToolUseResult {
|
|
|
884
528
|
/** Appended to the result as a `<system-reminder>` the model can read. */
|
|
885
529
|
additionalContext?: string;
|
|
886
530
|
}
|
|
887
|
-
/** #281 件A — the context of a {@link Hooks.userPromptSubmit} invocation (second parameter,
|
|
888
|
-
* additive). An object so later additions stay additive; design/373 §4.3 (D2) grew the
|
|
889
|
-
* entrance-discrimination trio below. */
|
|
890
|
-
export interface UserPromptSubmitContext {
|
|
891
|
-
/** The run/leg identity envelope — see {@link HookInvocationIdentity} for the presence law. */
|
|
892
|
-
identity?: HookInvocationIdentity;
|
|
893
|
-
/** {@link HookToolContext.permissionMode} (absent on `"resume_message"`, screened before the leg exists). */
|
|
894
|
-
permissionMode?: PermissionMode;
|
|
895
|
-
/** {@link HookSeatSignal} — this invocation's own abort signal. */
|
|
896
|
-
signal?: AbortSignal;
|
|
897
|
-
/**
|
|
898
|
-
* design/373 §4.3 (D2) — WHICH user-lane entrance this text is entering through. The screen now
|
|
899
|
-
* sits at every user-lane entrance, so a hook that used to see only the objective can (and, if it
|
|
900
|
-
* blocks unconditionally, MUST) branch on this: `"objective"` = the task's opening prompt (the
|
|
901
|
-
* pre-373 only caller); `"steer"` = a live mid-run TaskStream.steer; `"resume_message"` = the
|
|
902
|
-
* message riding a wake resume (screened at the verb, pre-CAS); `"parked_redelivery"` = a parked
|
|
903
|
-
* steer being re-screened on the CURRENT process's hook when a resume redelivers it — ANY resume
|
|
904
|
-
* kind that drains parked steers (policy_ask / dry_run_review / plan_review / resource_limit,
|
|
905
|
-
* wake included), because a park's screening cannot be carried across processes (hooks are
|
|
906
|
-
* process-local config). ⚠️ DOUBLE ARRIVAL IS CONTRACTUAL:
|
|
907
|
-
* the same input can reach a hook twice with different sources (screened live as `"steer"`,
|
|
908
|
-
* parked, re-screened as `"parked_redelivery"`); idempotency is the hook's to hold — a stateful
|
|
909
|
-
* hook keys on {@link inputId}. `"followUp"` is a RESERVED spelling (spec seat only): the Runner
|
|
910
|
-
* face has no user-lane followUp verb today, so no invocation carries it yet — if/when that face
|
|
911
|
-
* lands it arrives screened under this name (never a silent widening).
|
|
912
|
-
* Absent ⇒ an emission from a pre-373 engine (old engines stamped nothing); every current engine
|
|
913
|
-
* seat stamps its name, so treat absence as "version unknown", never as a sixth entrance.
|
|
914
|
-
*/
|
|
915
|
-
source?: "objective" | "steer" | "resume_message" | "followUp" | "parked_redelivery";
|
|
916
|
-
/**
|
|
917
|
-
* design/373 §4.3 (D2) — the screened input's correlation id. Present on EVERY entrance except
|
|
918
|
-
* the objective seat (no id exists on that face — nothing is fabricated there):
|
|
919
|
-
* - `"steer"` — the effective `inputId` (caller-supplied or engine-minted — the SAME id the
|
|
920
|
-
* `human_input` event and any parked copy carry);
|
|
921
|
-
* - `"parked_redelivery"` — the parked entry's STORED id (stable across redeliveries);
|
|
922
|
-
* - `"resume_message"` — always present too: the caller's id verbatim when it supplied one,
|
|
923
|
-
* otherwise MINTED PER CALL by the wake validator. ⚠️ Per call, not per message: a retried wake
|
|
924
|
-
* that supplies no caller id and REACHES this seat re-screens identical text under a FRESH id.
|
|
925
|
-
* A dedup/quota hook keying its ledger here gets cross-attempt stability only when the CALLER
|
|
926
|
-
* supplies the id — a host that retries wakes should mint its own. What the engine guarantees
|
|
927
|
-
* instead (#472) is that the seat is not reached needlessly: it sits BELOW every retryable
|
|
928
|
-
* pre-CAS refusal on the resume ladder, so an attempt the engine was going to refuse anyway
|
|
929
|
-
* (a full governance window most of all) costs ZERO invocations — the retry loop that refusal
|
|
930
|
-
* invites cannot bill this hook per attempt.
|
|
931
|
-
* This is the dedup key for the double-arrival contract on {@link source}: a quota-charging hook
|
|
932
|
-
* that must not double-charge one input keys its ledger here.
|
|
933
|
-
*/
|
|
934
|
-
inputId?: string;
|
|
935
|
-
/**
|
|
936
|
-
* design/373 §4.3 (D2) — the API-boundary actor snapshot attributed to this input (the same
|
|
937
|
-
* snapshot the `human_input` event reports), when the caller supplied one. Attribution only,
|
|
938
|
-
* never authority — a hook wanting to exempt its own supervisor lane branches on this PLUS
|
|
939
|
-
* {@link source}, and absence means "anonymous caller", exactly as on the event face.
|
|
940
|
-
*/
|
|
941
|
-
actor?: ActorAssertion;
|
|
942
|
-
/**
|
|
943
|
-
* The files declared on this objective (`TaskSpec.userAttachments`), in order — present only on `source:"objective"`
|
|
944
|
-
* when the objective declares any. A path entry shows its path; a host entry its name and byte count, never its
|
|
945
|
-
* bytes. Blocking the objective reads and delivers none of them. A hook does not govern the engine's reading of an
|
|
946
|
-
* allowed attachment (PreToolUse does not run for it either): a deployment that must keep a path from the model
|
|
947
|
-
* writes a deny rule, which the attachment read honors like the Read tool does.
|
|
948
|
-
*/
|
|
949
|
-
userAttachments?: readonly import("./user-attachment.js").UserAttachmentDeclaration[];
|
|
950
|
-
}
|
|
951
|
-
/** #281 件A — the context of a {@link Hooks.postToolBatch} invocation (third parameter, additive —
|
|
952
|
-
* deliberately NOT folded into `meta`, whose presence already means "the engine injected here"). */
|
|
953
|
-
export interface PostToolBatchContext {
|
|
954
|
-
/** The run/leg identity envelope — see {@link HookInvocationIdentity} for the presence law. */
|
|
955
|
-
identity?: HookInvocationIdentity;
|
|
956
|
-
/** {@link HookToolContext.permissionMode}. */
|
|
957
|
-
permissionMode?: PermissionMode;
|
|
958
|
-
/** {@link HookSeatSignal} — this invocation's own abort signal. */
|
|
959
|
-
signal?: AbortSignal;
|
|
960
|
-
}
|
|
961
531
|
/** A UserPromptSubmit hook result: block the submission, or inject context ahead of the prompt. */
|
|
962
532
|
export interface UserPromptSubmitResult {
|
|
963
533
|
/** Block submission entirely; the task fails with this model-readable reason. */
|
|
@@ -980,7 +550,9 @@ export interface ToolGateResult {
|
|
|
980
550
|
* frame, and the deny observer receives the same object: one mint, three faces.
|
|
981
551
|
*/
|
|
982
552
|
gate?: GateOutcome;
|
|
983
|
-
/**
|
|
553
|
+
/** The args to execute with — the pass's own immutable copy, the value every judge of the call read (the model's args
|
|
554
|
+
* as taken at the gate's entry, or what a hook, a policy or a person rewrote them to); re-validated by the loop. Present
|
|
555
|
+
* on every allow exit, whether or not anything rewrote (compare values to tell); absent on a block and a suspend. */
|
|
984
556
|
updatedInput?: unknown;
|
|
985
557
|
/** The input this pass decided on (what a refusal refused, what an allowed call runs with) as a deep, FROZEN copy taken
|
|
986
558
|
* at the exit — never the live args. Beside {@link gate} on both terminal exits; absent on the suspend exit. The deny
|
|
@@ -1020,18 +592,8 @@ export interface ToolGateResult {
|
|
|
1020
592
|
*/
|
|
1021
593
|
export type ContentAskOutcome = {
|
|
1022
594
|
kind: "answered";
|
|
1023
|
-
/** The EXACT batch that was put in front of the person, retained by the resolver as an isolated
|
|
1024
|
-
* snapshot. The gate executes this and nothing else, so "what was shown" and "what runs" are the
|
|
1025
|
-
* same object graph by construction rather than by two parties agreeing not to mutate one. */
|
|
1026
|
-
presentedInput: unknown;
|
|
1027
595
|
} | {
|
|
1028
596
|
kind: "unavailable";
|
|
1029
|
-
/** The retained snapshot, when the resolver got far enough to make one (i.e. it actually waited
|
|
1030
|
-
* on a callback). The park persists THIS, not the caller's live object: the wait is a window in
|
|
1031
|
-
* which whoever owns the rewrite can change it, and a checkpoint holding bytes the gate never
|
|
1032
|
-
* adjudicated is one a later human would answer as a different question. Absent when no wait
|
|
1033
|
-
* happened, in which case there is no window and the live object is still the validated one. */
|
|
1034
|
-
presentedInput?: unknown;
|
|
1035
597
|
/** True iff the park closure took its SYNC-FIRST DECLINE for this call — it has not yet made a
|
|
1036
598
|
* real suspend attempt, so re-entering it now IS that attempt rather than a second one. False
|
|
1037
599
|
* when the park already had its attempt (no live face to prefer, or a durable mandate): the gate
|
|
@@ -1042,11 +604,6 @@ export type ContentAskOutcome = {
|
|
|
1042
604
|
} | {
|
|
1043
605
|
kind: "delivery_failure";
|
|
1044
606
|
code: string;
|
|
1045
|
-
/** The retained snapshot, when the resolver got far enough to make one. Executed for the same
|
|
1046
|
-
* reason the answered arm's is: the bound failure names the batch it belongs to, and executing a
|
|
1047
|
-
* different one would drop it and re-ask the person. Absent when the refusal happened before a
|
|
1048
|
-
* snapshot could be taken. */
|
|
1049
|
-
presentedInput?: unknown;
|
|
1050
607
|
};
|
|
1051
608
|
/**
|
|
1052
609
|
* A durable park that was ATTEMPTED for this call and could not be minted, carrying the reason in the
|
|
@@ -1176,7 +733,7 @@ export interface ToolGateInput extends PermissionSeatInputs, SkillGateSeats, All
|
|
|
1176
733
|
toolName: string;
|
|
1177
734
|
input: Record<string, unknown>;
|
|
1178
735
|
};
|
|
1179
|
-
/**
|
|
736
|
+
/** The run/leg identity envelope, put verbatim on every {@link PreToolUseEvent} this
|
|
1180
737
|
* gate call builds and on every {@link PermissionDeniedPayload} it emits. The Runner supplies its
|
|
1181
738
|
* per-leg mint; a host driving the gate directly may omit it, and the contexts then carry no
|
|
1182
739
|
* identity (honest absence — this layer never fabricates a leg). */
|
|
@@ -1185,30 +742,31 @@ export interface ToolGateInput extends PermissionSeatInputs, SkillGateSeats, All
|
|
|
1185
742
|
* reasons ride `formatHookFeedback`, so their open tags must carry the same mark the run's
|
|
1186
743
|
* system-prompt declaration names. Absent (a host driving the gate directly) ⇒ bare tags. */
|
|
1187
744
|
reminderMark?: string;
|
|
1188
|
-
preToolUse?: Hooks["preToolUse"];
|
|
1189
745
|
/**
|
|
1190
|
-
* The
|
|
1191
|
-
*
|
|
1192
|
-
* ⇒
|
|
1193
|
-
*
|
|
1194
|
-
*
|
|
1195
|
-
* On elapse the screening FAILS CLOSED — the call does not execute — and the block reason names the
|
|
1196
|
-
* hook and the bound. That direction is not a new posture for this seat: a hook that THROWS is
|
|
1197
|
-
* already the fail-closed deny here, and a hook that never answers has told the gate strictly less
|
|
1198
|
-
* than one that crashed. A face the deployment declared observational is not exempt, for the same
|
|
1199
|
-
* reason its throw is not: the declaration says its VERDICTS do not count, and a wait that never
|
|
1200
|
-
* ends is not a verdict.
|
|
746
|
+
* The leg's mods bus: phase 1, the approved-edit re-screen and (through the Runner) the approved-call re-screen raise
|
|
747
|
+
* `classic.PreToolUse` on it; the lanes raise `tool.check` (once per adjudication, never over a deny). Absent, or no
|
|
748
|
+
* handler on the event ⇒ nothing raised. A handler that throws, runs past its budget or breaks the site's contract refuses
|
|
749
|
+
* the call fail-closed (the event's failure column), and so does a cancel; an observe handler never decides.
|
|
1201
750
|
*/
|
|
1202
|
-
|
|
1203
|
-
/** The
|
|
1204
|
-
*
|
|
751
|
+
modBus?: Pick<import("./mods/kernel/index.js").ModBus, "hasHandlers" | "dispatch">;
|
|
752
|
+
/** The inherited installations whose `tool.check` judges this leg's calls too (`inheritedToolChecks`, the rule's one home):
|
|
753
|
+
* raised after {@link modBus}, each over the verdict the previous left standing, read by the one comparison — their `allow`
|
|
754
|
+
* never clears an ask (a constraint only tightens), and their `ask` goes to each installation's own `settle` (where its
|
|
755
|
+
* installation froze the question), never to this gate's resolver; an approval there that edits the call takes this gate's
|
|
756
|
+
* approved-edit pass. Absent ⇒ only {@link modBus} is raised. */
|
|
757
|
+
inheritedToolChecks?: readonly import("./mods/stations.js").InheritedToolCheck[];
|
|
758
|
+
/** The leg's observed permission mode, carried on every `classic.PreToolUse` e this gate call raises. Absent ⇒ the e
|
|
759
|
+
* carries none (a host-driven gate with no leg seat). */
|
|
760
|
+
observedPermissionMode?: () => PermissionMode;
|
|
761
|
+
/** The task's live tracked cwd reader, put on every {@link PreToolUseEvent} this gate call raises
|
|
762
|
+
* (see {@link PreToolUseEvent.cwd}). A FUNCTION rather than a string for the reason the policy's own
|
|
1205
763
|
* threading gives: capturing the value when the gate's wiring is built would freeze the task's
|
|
1206
764
|
* starting directory and answer for a run that has since `cd`ed. Absent ⇒ the contexts carry no
|
|
1207
765
|
* `cwd`, which is the honest answer for a run with no tracked one. */
|
|
1208
766
|
trackedCwd?: () => string | undefined;
|
|
1209
767
|
/** The leg's target-reading stamp, applied where the gate's request is minted over the final args (a rewrite re-reads it: `withArgsReading`). */
|
|
1210
768
|
stampCallTarget?: CallTargetStamp;
|
|
1211
|
-
/** The read-only env capability face put on every {@link
|
|
769
|
+
/** The read-only env capability face put on every {@link PreToolUseEvent} this gate call
|
|
1212
770
|
* builds ({@link HookEnvCapabilities}). Built ONCE per task by the runner (after the env is minted) and
|
|
1213
771
|
* passed through unchanged; omitted when the deployment wired no execution environment. */
|
|
1214
772
|
hookEnv?: HookEnvCapabilities;
|
|
@@ -1383,27 +941,22 @@ export interface ToolGateInput extends PermissionSeatInputs, SkillGateSeats, All
|
|
|
1383
941
|
* (timeout/cancel) in addition to {@link approvalTimeoutMs}; an abort while probing fails closed to `ask`. */
|
|
1384
942
|
abortSignal?: AbortSignal;
|
|
1385
943
|
/**
|
|
1386
|
-
* design/134 R5: observer for the gate's DENY short-circuit (
|
|
1387
|
-
*
|
|
944
|
+
* design/134 R5: a host's own observer for the gate's DENY short-circuit (the Runner's are its leg's handlers on
|
|
945
|
+
* {@link modBus}), run as one more observe handler of `classic.PermissionDenied` — that station's columns; a failure
|
|
946
|
+
* is disclosed on {@link onNotifyError} as `toolGate.permissionDenied`. Fired ONCE, at the single deny exit of the
|
|
1388
947
|
* adjudicate chain — a policy deny or a resolved-ask deny. NOT fired for a PreToolUse hook deny (the
|
|
1389
|
-
* exclusion on {@link
|
|
1390
|
-
* claim) or a durable suspend (the ask path).
|
|
1391
|
-
* must never alter the deny outcome.
|
|
948
|
+
* exclusion on {@link PermissionDeniedPayload}, which also records why that exclusion is not a parity
|
|
949
|
+
* claim) or a durable suspend (the ask path).
|
|
1392
950
|
*
|
|
1393
951
|
* ALSO fired for the engine's fail-closed interception of a THROWING PreToolUse hook, with
|
|
1394
952
|
* `source:"hook"` — the exclusion is the hook's own deny DECISION, not an engine decision.
|
|
1395
953
|
*/
|
|
1396
954
|
permissionDenied?: (payload: PermissionDeniedPayload) => void | Promise<void>;
|
|
1397
955
|
/**
|
|
1398
|
-
* Trace sink for a
|
|
1399
|
-
*
|
|
1400
|
-
*
|
|
1401
|
-
*
|
|
1402
|
-
* (a throwing sink is swallowed).
|
|
1403
|
-
*
|
|
1404
|
-
* ALSO fired for a {@link reversibilityProbe} that threw or timed out (same species — a
|
|
1405
|
-
* deployment-supplied callback failing while the gate holds the fail-closed line) and for a
|
|
1406
|
-
* malformed {@link approvalTimeoutMs} refused to the bounded default. A task-abort rejection
|
|
956
|
+
* Trace sink for a deployment-supplied callback of this gate that failed while the gate holds the fail-closed line
|
|
957
|
+
* — a {@link reversibilityProbe} that threw or timed out — and for a malformed {@link approvalTimeoutMs} refused to
|
|
958
|
+
* the bounded default (`onError(phase:"hook")`, wired by the caller). A failed `classic.PreToolUse` handler is
|
|
959
|
+
* reported by the bus itself. Never affects the outcome (a throwing sink is swallowed). A task-abort rejection
|
|
1407
960
|
* mid-probe is NOT reported (normal cancellation, not a defect).
|
|
1408
961
|
*/
|
|
1409
962
|
onHookError?: (err: unknown) => void;
|
|
@@ -1733,56 +1286,52 @@ export interface ToolGateInput extends PermissionSeatInputs, SkillGateSeats, All
|
|
|
1733
1286
|
};
|
|
1734
1287
|
}
|
|
1735
1288
|
/**
|
|
1736
|
-
*
|
|
1737
|
-
*
|
|
1289
|
+
* The PreToolUse screening face ({@link PreToolUseScreening}) for ONE call — `classic.PreToolUse` raised on the leg's
|
|
1290
|
+
* bus, the per-screening e and the fail-closed sentences, built in ONE place for every site that screens a call: the
|
|
1291
|
+
* gate's phase 1 and approved-edit re-screen (through {@link runToolGate}'s pass) and the resumed leg's re-screen of an
|
|
1292
|
+
* approved call. Undefined when no handler hangs on the event.
|
|
1738
1293
|
*
|
|
1739
|
-
*
|
|
1740
|
-
*
|
|
1741
|
-
*
|
|
1742
|
-
|
|
1743
|
-
|
|
1294
|
+
* The e: `tool` (the call's wire name), `tool_use_id`, `input` — a deep-frozen copy of the args, so what a handler
|
|
1295
|
+
* judges is what runs (`input` is pinned; a rewrite is the answer's `updatedInput`) — `agentId` on a delegated leg,
|
|
1296
|
+
* `cwd` (the task's tracked cwd, read per screening), `env` (the capability face), `identity`, `permissionMode`.
|
|
1297
|
+
*/
|
|
1298
|
+
export declare function createPreToolUseScreening(input: Pick<ToolGateInput, "event" | "modBus" | "observedPermissionMode" | "trackedCwd" | "hookEnv" | "identity" | "abortSignal">): PreToolUseScreening | undefined;
|
|
1299
|
+
/**
|
|
1300
|
+
* Fold a leg's `classic.PreToolUse` chain into a {@link ToolPolicy} layer, so the screening a task installed can also
|
|
1301
|
+
* travel down a delegation chain as one more inherited constraint — the constraint MINT. `chain` is the installing
|
|
1302
|
+
* leg's bus; the policy raises `classic.PreToolUse` on it with the handlers that JUDGE (an observe handler never enters
|
|
1303
|
+
* a constraint — the participant filter below is that rule's one home).
|
|
1744
1304
|
*
|
|
1745
|
-
*
|
|
1746
|
-
*
|
|
1747
|
-
*
|
|
1748
|
-
*
|
|
1749
|
-
*
|
|
1750
|
-
* from a policy ask reads the same fact one level down — notably the persisted-rule lane, which must
|
|
1751
|
-
* not let a standing allow-rule resolve a screening ask;
|
|
1752
|
-
* - `allow`/`ask` with `updatedInput` → the same rewrite, which the fold cascades to later layers and
|
|
1753
|
-
* re-checks against the narrowing layers;
|
|
1754
|
-
* - a THROW → the fail-closed deny with the RB-442 attribution text (naming the hook and the
|
|
1755
|
-
* non-execution), because a screening face that cannot answer must not pass the call.
|
|
1305
|
+
* Why a policy and not a second channel: a delegated child already folds each ancestor's caller policy
|
|
1306
|
+
* (`InheritedGate.parentConstraints`), and that fold is where `deny > ask > allow`, the rewrite cascade, the
|
|
1307
|
+
* ancestor-frozen approver and the durable mandate all already live. Expressing the screening in the same shape means
|
|
1308
|
+
* the child gains no new decision channel — the existing fold consumes it — and the tighten-only property is
|
|
1309
|
+
* structural rather than restated.
|
|
1756
1310
|
*
|
|
1757
|
-
*
|
|
1758
|
-
*
|
|
1759
|
-
*
|
|
1760
|
-
*
|
|
1761
|
-
*
|
|
1762
|
-
*
|
|
1311
|
+
* The mapping mirrors the gate's own phase 1 decision for decision:
|
|
1312
|
+
* - no opinion → `allow`, contributing nothing;
|
|
1313
|
+
* - `deny` → `deny` in the fold's own words;
|
|
1314
|
+
* - `ask` → `ask`, stamped `decisionReason:"hook"` (and the mandate, when the answer set it) so every consumer that
|
|
1315
|
+
* distinguishes a screening ask from a policy ask reads the same fact one level down;
|
|
1316
|
+
* - `allow`/`ask` with `updatedInput` → the same rewrite, which the fold cascades and re-checks;
|
|
1317
|
+
* - a failed screening (a handler that threw, ran past its budget or broke the site's contract) or a cancel → the
|
|
1318
|
+
* fail-closed deny, because a screening that cannot answer must not pass the call. The installing leg's bus
|
|
1319
|
+
* already reported a crash or a timeout on that leg's error lane.
|
|
1763
1320
|
*
|
|
1764
|
-
*
|
|
1765
|
-
*
|
|
1766
|
-
*
|
|
1767
|
-
* it. (The decision half — the part that restricts — is what travels.)
|
|
1768
|
-
* - the phase-1 observer exclusion — a deny raised here is a fold deny, so the descendant's
|
|
1769
|
-
* `permissionDenied` observer sees it with `source:"policy"`. That exclusion is about a hook deciding
|
|
1770
|
-
* in ITS OWN gate; here the descendant's policy fold is what refused the call.
|
|
1321
|
+
* **Idempotency** ({@link combinePolicies}): a layer's `check` may run more than once for a single tool call (the fold
|
|
1322
|
+
* scans past an `ask`, a later rewrite re-runs the prefix, an approved edit is re-adjudicated), so a handler with a side
|
|
1323
|
+
* effect sees that call more than once on those paths. Its own leg's phase 1 has always had the third of these.
|
|
1771
1324
|
*
|
|
1772
|
-
*
|
|
1773
|
-
*
|
|
1774
|
-
*
|
|
1775
|
-
*
|
|
1776
|
-
*
|
|
1777
|
-
*
|
|
1325
|
+
* Not carried, and not reconstructible in this shape: `additionalContext` (a policy verdict has no channel for
|
|
1326
|
+
* model-facing text — the context belongs to the run whose gate ran it), the leg identity and the tracked cwd (the
|
|
1327
|
+
* fold's request carries neither, and the installing leg's would name the wrong run), and the phase-1 observer
|
|
1328
|
+
* exclusion (a deny raised here is a fold deny: the descendant's deny observer sees it as `source:"policy"`). `env` is
|
|
1329
|
+
* the capability face of the environment the chain was installed against, captured at the install site.
|
|
1330
|
+
*
|
|
1331
|
+
* The chain travels on the minted policy: a descendant's gate raises the installation's `tool.check` on it (a verdict read is
|
|
1332
|
+
* not a fold layer). A host re-supplying the entry hands back the policy minted here, as it is.
|
|
1778
1333
|
*/
|
|
1779
|
-
export declare function createPreToolUseConstraintPolicy(
|
|
1780
|
-
/** The install site's {@link Hooks.timeoutMs}. The folded form was ALREADY bounded by the descendant's
|
|
1781
|
-
* abort race — that asymmetry (bounded as an inherited constraint, unbounded in its own gate) is what
|
|
1782
|
-
* named the hole in the first place — but an abort bound is not a deadline: on a descendant with no
|
|
1783
|
-
* walltime and no cancel, the race never fires. So the same seat bound rides here too, and the two
|
|
1784
|
-
* installations of one callback are now bounded the same way for the same reason. */
|
|
1785
|
-
timeoutMs?: number): ToolPolicy;
|
|
1334
|
+
export declare function createPreToolUseConstraintPolicy(chain: Pick<import("./mods/kernel/index.js").ModBus, "hasHandlers" | "dispatch">, env?: HookEnvCapabilities): ToolPolicy;
|
|
1786
1335
|
/**
|
|
1787
1336
|
* The park closure's ONE structural seat — what the gate hands the durable park beyond the twelve
|
|
1788
1337
|
* positional seats. Every member is optional and read by name, so a new thing the park must know
|
|
@@ -1831,13 +1380,6 @@ export declare function askCarryRowMembers(carry: AskCarry | undefined): {
|
|
|
1831
1380
|
askClass?: import("./ask-origin.js").AskClass;
|
|
1832
1381
|
classes?: readonly import("./ask-origin.js").AskClass[];
|
|
1833
1382
|
};
|
|
1834
|
-
/**
|
|
1835
|
-
* The PreToolUse screening seat ({@link PreToolUseScreening}) for ONE call — seat runner, seat bound, per-screening
|
|
1836
|
-
* context and the fail-closed / deny sentences, built in ONE place for every site that screens a call: the gate's
|
|
1837
|
-
* phase 1 and approved-edit re-screen (through {@link runToolGate}'s pass) and the resumed leg's re-screen of an
|
|
1838
|
-
* approved call. Undefined when no face is wired. `hookSeatMs` is the caller's validated bound.
|
|
1839
|
-
*/
|
|
1840
|
-
export declare function createPreToolUseScreening(preToolUse: Hooks["preToolUse"] | undefined, input: Pick<ToolGateInput, "event" | "trackedCwd" | "hookEnv" | "identity" | "onHookError" | "abortSignal">, hookSeatMs: number, notifier: SafeNotifier): PreToolUseScreening | undefined;
|
|
1841
1383
|
/**
|
|
1842
1384
|
* The design/37 **two-phase tool gate** — the single chokepoint that makes the load-bearing invariant
|
|
1843
1385
|
* structural: a hook's `allow` passes no deny, no ask rule and no mandated question; it is one member of the
|