@sema-agent/core 7.51.2 → 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 +504 -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.js +6 -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 +40 -8
- package/dist/core/allow-entry.js +23 -16
- 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/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 +16 -0
- package/dist/core/mcp.d.ts +11 -7
- package/dist/core/mcp.js +11 -5
- 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 +17 -15
- package/dist/core/runner/prepare-policy-chain.js +95 -100
- 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 +5 -5
- package/dist/core/runner/session-rule-policy.js +13 -8
- 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 +88 -20
- package/dist/core/secret-env.js +192 -38
- package/dist/core/session-policy-store.d.ts +52 -16
- package/dist/core/session-policy-store.js +118 -28
- 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/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 +20 -16
- package/dist/index.js +13 -11
- 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/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 +242 -99
- 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.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { decisionText, describeThrown,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { traceHookCrash } from "./gate-crash-trace.js";
|
|
1
|
+
import { abortedSeatDeny, decisionText, describeThrown, isEngineRefusal, ownArgs, refuseOutOfContractDecision, unaskedSeatAnswer } from "./tool-policy.js";
|
|
2
|
+
import { createSettlementLedger, engineFailClosedExit, hookDenyExit, unownedArgsExit } from "./runner/gate-exit.js";
|
|
3
|
+
import { classicEventBase, dispatchClassic, ENGINE_CORE_ANSWER, engineCore, failedHandlerClause, judgedInputOf, observePermissionDenied, recordScreeningChain } from "./mods/stations.js";
|
|
5
4
|
import { runGateFold } from "./gate-fold.js";
|
|
6
5
|
import { runGateLanes } from "./gate-lanes.js";
|
|
7
6
|
export { normalizeOrgGateVerdict, normalizePersistedRuleHit } from "./rule-lane-reads.js";
|
|
8
|
-
export { cloneObserverInput } from "./runner/gate-exit.js";
|
|
9
7
|
import { brandPolicyAskClass } from "./ask-class.js";
|
|
10
8
|
import { isAskOrigin, screenAskClassMembers } from "./ask-origin.js";
|
|
11
9
|
import { isAutoModeFallbackCause } from "./auto-mode.js";
|
|
@@ -13,92 +11,6 @@ import { inlineUntrusted } from "./untrusted-text.js";
|
|
|
13
11
|
export { formatHookFeedback } from "./reminder-mint.js";
|
|
14
12
|
import { createSafeNotifier } from "./safe-notify.js";
|
|
15
13
|
import { wireOf } from "./tool-name-readings.js";
|
|
16
|
-
export const DEFAULT_HOOK_TIMEOUT_MS = 600_000;
|
|
17
|
-
export const MAX_HOOK_TIMEOUT_MS = 2_147_483_647;
|
|
18
|
-
const POST_ABORT_GRACE_MS = 1_000;
|
|
19
|
-
export function postAbortGraceMs(remainingMs) {
|
|
20
|
-
return Math.max(0, Math.min(POST_ABORT_GRACE_MS, remainingMs));
|
|
21
|
-
}
|
|
22
|
-
const badHookTimeoutReported = new WeakSet();
|
|
23
|
-
export function resolveHookTimeoutMs(supplied, report, owner) {
|
|
24
|
-
if (supplied === undefined)
|
|
25
|
-
return DEFAULT_HOOK_TIMEOUT_MS;
|
|
26
|
-
if (Number.isFinite(supplied) && supplied >= 0 && supplied <= MAX_HOOK_TIMEOUT_MS)
|
|
27
|
-
return supplied;
|
|
28
|
-
if (report !== undefined && !(owner !== undefined && badHookTimeoutReported.has(owner))) {
|
|
29
|
-
if (owner !== undefined)
|
|
30
|
-
badHookTimeoutReported.add(owner);
|
|
31
|
-
try {
|
|
32
|
-
report(new Error(`Hooks.timeoutMs must be a non-negative finite number no greater than ${MAX_HOOK_TIMEOUT_MS} (got ${String(supplied)}) — ` +
|
|
33
|
-
`every hook seat falls back to the ${DEFAULT_HOOK_TIMEOUT_MS}ms default`));
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return DEFAULT_HOOK_TIMEOUT_MS;
|
|
39
|
-
}
|
|
40
|
-
export async function runHookSeat(seat, bound, call) {
|
|
41
|
-
void seat;
|
|
42
|
-
const timeoutMs = resolveHookTimeoutMs(bound.timeoutMs, bound.onBadTimeout, bound.owner);
|
|
43
|
-
const taskSignal = bound.signal;
|
|
44
|
-
const controller = new AbortController();
|
|
45
|
-
const pending = Promise.resolve(call(controller.signal));
|
|
46
|
-
const startedAt = performance.now();
|
|
47
|
-
return await new Promise((resolve, reject) => {
|
|
48
|
-
let settled = false;
|
|
49
|
-
let listening = false;
|
|
50
|
-
let timer;
|
|
51
|
-
const clearTimer = () => {
|
|
52
|
-
if (timer !== undefined)
|
|
53
|
-
clearTimeout(timer);
|
|
54
|
-
timer = undefined;
|
|
55
|
-
};
|
|
56
|
-
const finish = (act) => {
|
|
57
|
-
if (settled)
|
|
58
|
-
return;
|
|
59
|
-
settled = true;
|
|
60
|
-
clearTimer();
|
|
61
|
-
if (listening)
|
|
62
|
-
taskSignal?.removeEventListener("abort", onAbort);
|
|
63
|
-
act();
|
|
64
|
-
};
|
|
65
|
-
const expire = (cause) => finish(() => {
|
|
66
|
-
void pending.then(undefined, () => {
|
|
67
|
-
});
|
|
68
|
-
resolve({ expired: true, cause });
|
|
69
|
-
queueMicrotask(() => {
|
|
70
|
-
try {
|
|
71
|
-
controller.abort();
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
const collapseToGrace = () => {
|
|
78
|
-
if (settled)
|
|
79
|
-
return;
|
|
80
|
-
clearTimer();
|
|
81
|
-
timer = setTimeout(() => expire("aborted"), postAbortGraceMs(timeoutMs - (performance.now() - startedAt)));
|
|
82
|
-
};
|
|
83
|
-
const onAbort = () => (bound.abortEnds === true ? expire("aborted") : collapseToGrace());
|
|
84
|
-
timer = setTimeout(() => expire("timeout"), timeoutMs);
|
|
85
|
-
if (taskSignal !== undefined) {
|
|
86
|
-
if (taskSignal.aborted) {
|
|
87
|
-
onAbort();
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
taskSignal.addEventListener("abort", onAbort, { once: true });
|
|
91
|
-
listening = true;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
pending.then((value) => finish(() => resolve({ expired: false, value })), (err) => finish(() => reject(asThrownError(err))));
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
export function hookSeatExpiredError(seat, timeoutMs, cause, consequence) {
|
|
98
|
-
return new Error(cause === "timeout"
|
|
99
|
-
? `the deployment's ${seat} hook did not answer within its ${timeoutMs}ms bound (Hooks.timeoutMs) — ${consequence}`
|
|
100
|
-
: `the deployment's ${seat} hook had not answered when the task was cancelled — ${consequence}`);
|
|
101
|
-
}
|
|
102
14
|
const reflectApply = Reflect.apply;
|
|
103
15
|
const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
|
104
16
|
const getPrototypeOf = Object.getPrototypeOf;
|
|
@@ -174,54 +86,92 @@ export function mintHookInvocationIdentity(facts) {
|
|
|
174
86
|
...(facts.parentToolCallId !== undefined ? { parentToolCallId: facts.parentToolCallId } : {}),
|
|
175
87
|
}));
|
|
176
88
|
}
|
|
177
|
-
function
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
`same hook and fails the same way. Hook error: ${cause || "(no message)"}`);
|
|
89
|
+
function screenPreToolUseResult(r) {
|
|
90
|
+
if (r === undefined || r === null || r === false)
|
|
91
|
+
return r;
|
|
92
|
+
return refuseOutOfContractDecision(r, { reasonIsNonInput: true });
|
|
182
93
|
}
|
|
183
|
-
function
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
: `the task was cancelled while a PreToolUse hook was still screening ${subject}; the call was NOT executed ` +
|
|
189
|
-
`(fail-closed). No verdict was reached — this is the run ending, not the tool failing.`;
|
|
94
|
+
function preToolUseAnswerViolation(answer) {
|
|
95
|
+
const r = screenPreToolUseResult(answer);
|
|
96
|
+
if (r === undefined || r === null || r === false || !isEngineRefusal(r))
|
|
97
|
+
return undefined;
|
|
98
|
+
return typeof r.message === "string" ? r.message : "the PreToolUse answer was refused by the engine";
|
|
190
99
|
}
|
|
191
|
-
function
|
|
192
|
-
if (
|
|
100
|
+
function preToolUseRefusedReason(subject, failed) {
|
|
101
|
+
if (failed === undefined) {
|
|
102
|
+
return `the task was cancelled while a PreToolUse hook was still screening ${subject}; the call was NOT executed ` + `(fail-closed). No verdict was reached — this is the run ending, not the tool failing.`;
|
|
103
|
+
}
|
|
104
|
+
const tail = failed.cause === "threw"
|
|
105
|
+
? ` This is a failure of the deployment's hook, NOT of the tool itself — an identical retry reaches the same hook and fails the same way.`
|
|
106
|
+
: failed.cause === "timeout"
|
|
107
|
+
? ` This is a failure of the deployment's hook, NOT of the tool itself — the screening face never returned a verdict, so nothing was decided about this call either way.`
|
|
108
|
+
: "";
|
|
109
|
+
return `a PreToolUse hook ${failedHandlerClause(failed)} while screening ${subject}; the call was NOT executed (fail-closed).${tail}`;
|
|
110
|
+
}
|
|
111
|
+
export function createPreToolUseScreening(input) {
|
|
112
|
+
const bus = input.modBus;
|
|
113
|
+
if (bus === undefined || !bus.hasHandlers("classic.PreToolUse"))
|
|
193
114
|
return undefined;
|
|
194
|
-
|
|
115
|
+
const { toolCallId, toolName } = input.event;
|
|
116
|
+
const screenedName = wireOf("gate.preToolUse", input.event);
|
|
117
|
+
const eventOf = (args) => {
|
|
118
|
+
const cwd = input.trackedCwd?.();
|
|
119
|
+
return {
|
|
120
|
+
...classicEventBase(input.identity, input.observedPermissionMode?.()),
|
|
121
|
+
tool: screenedName,
|
|
122
|
+
tool_use_id: toolCallId,
|
|
123
|
+
input: judgedInputOf(args),
|
|
124
|
+
...(typeof cwd === "string" ? { cwd } : {}),
|
|
125
|
+
...(input.hookEnv !== undefined ? { env: input.hookEnv } : {}),
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
screen: async (args, subject) => {
|
|
130
|
+
let outcome;
|
|
131
|
+
try {
|
|
132
|
+
outcome = await dispatchClassic(bus, "classic.PreToolUse", eventOf(args), { ...(input.abortSignal !== undefined ? { signal: input.abortSignal } : {}), checkAnswer: preToolUseAnswerViolation });
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
return { kind: "refused", reason: preToolUseRefusedReason(subject, { kind: "failed", registration: "engine", cause: "threw", reason: `could not raise the screening: ${describeThrown(err)}`, skipped: [] }) };
|
|
136
|
+
}
|
|
137
|
+
if (outcome === undefined || outcome.kind === "aborted")
|
|
138
|
+
return { kind: "refused", reason: preToolUseRefusedReason(subject, undefined) };
|
|
139
|
+
if (outcome.kind === "failed")
|
|
140
|
+
return { kind: "refused", reason: preToolUseRefusedReason(subject, outcome) };
|
|
141
|
+
const r = screenPreToolUseResult(outcome.answer);
|
|
142
|
+
return { kind: "answered", answer: r === null || r === false ? undefined : r, ...(outcome.answeredBy !== undefined ? { answeredBy: outcome.answeredBy } : {}) };
|
|
143
|
+
},
|
|
144
|
+
deniedReason: (answer) => decisionText(answer) ?? `tool "${toolName}" blocked by a PreToolUse hook`,
|
|
145
|
+
};
|
|
195
146
|
}
|
|
196
|
-
export function createPreToolUseConstraintPolicy(
|
|
197
|
-
|
|
147
|
+
export function createPreToolUseConstraintPolicy(chain, env) {
|
|
148
|
+
const judges = (p) => !p.observe;
|
|
149
|
+
const minted = brandPolicyAskClass({
|
|
198
150
|
check: async (req, signal) => {
|
|
151
|
+
if (!chain.hasHandlers("classic.PreToolUse", judges))
|
|
152
|
+
return { action: "allow" };
|
|
199
153
|
const unasked = unaskedSeatAnswer(req, signal, { aborted: `the inherited PreToolUse screening of "${req.toolName}" was not consulted: the run or turn was already interrupted`, unreachable: `the inherited PreToolUse screening of "${req.toolName}" was not consulted: nobody can be asked about this call` }, "hook");
|
|
200
154
|
if (unasked !== undefined)
|
|
201
155
|
return unasked;
|
|
202
|
-
|
|
203
|
-
|
|
156
|
+
const subject = `this call to "${req.toolName}"`;
|
|
157
|
+
let outcome;
|
|
204
158
|
try {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
return { action: "deny", message: preToolUseUnansweredReason(`this call to "${req.toolName}"`, boundMs, seat.cause), decisionReason: "hook" };
|
|
213
|
-
}
|
|
214
|
-
r = screenPreToolUseResult(seat.value);
|
|
159
|
+
outcome = await chain.dispatch("classic.PreToolUse", { tool: req.toolName, tool_use_id: req.toolCallId, input: judgedInputOf(req.args), ...(env !== undefined ? { env } : {}) }, {
|
|
160
|
+
bottom: engineCore,
|
|
161
|
+
participant: judges,
|
|
162
|
+
...(signal !== undefined ? { signal } : {}),
|
|
163
|
+
checkAnswer: (a) => (a === ENGINE_CORE_ANSWER ? undefined : preToolUseAnswerViolation(a)),
|
|
164
|
+
});
|
|
215
165
|
}
|
|
216
166
|
catch (err) {
|
|
217
|
-
|
|
218
|
-
onCrash?.(err);
|
|
219
|
-
}
|
|
220
|
-
catch {
|
|
221
|
-
}
|
|
222
|
-
return { action: "deny", message: preToolUseCrashReason(`this call to "${req.toolName}"`, err), decisionReason: "hook" };
|
|
167
|
+
return { action: "deny", message: preToolUseRefusedReason(subject, { kind: "failed", registration: "engine", cause: "threw", reason: `could not raise the screening: ${describeThrown(err)}`, skipped: [] }), decisionReason: "hook" };
|
|
223
168
|
}
|
|
224
|
-
if (
|
|
169
|
+
if (outcome.kind === "aborted")
|
|
170
|
+
return abortedSeatDeny(req, `the inherited PreToolUse screening of "${req.toolName}" ended when the run or turn was interrupted`, "hook");
|
|
171
|
+
if (outcome.kind === "failed")
|
|
172
|
+
return { action: "deny", message: preToolUseRefusedReason(subject, outcome), decisionReason: "hook" };
|
|
173
|
+
const r = screenPreToolUseResult(outcome.answer);
|
|
174
|
+
if (r === undefined || r === null || r === false)
|
|
225
175
|
return { action: "allow" };
|
|
226
176
|
if (r.action === "deny") {
|
|
227
177
|
return { action: "deny", message: decisionText(r) ?? `tool "${req.toolName}" blocked by a PreToolUse hook`, decisionReason: "hook" };
|
|
@@ -239,6 +189,8 @@ export function createPreToolUseConstraintPolicy(preToolUse, env, onCrash, timeo
|
|
|
239
189
|
return r.updatedInput !== undefined ? { action: "allow", updatedInput: r.updatedInput, ...stated } : { action: "allow", ...stated };
|
|
240
190
|
},
|
|
241
191
|
}, "hook");
|
|
192
|
+
recordScreeningChain(minted, chain);
|
|
193
|
+
return minted;
|
|
242
194
|
}
|
|
243
195
|
export function askCarryRowMembers(carry) {
|
|
244
196
|
if (carry === undefined)
|
|
@@ -253,54 +205,21 @@ export function askCarryRowMembers(carry) {
|
|
|
253
205
|
...(classed !== undefined ? classed : {}),
|
|
254
206
|
};
|
|
255
207
|
}
|
|
256
|
-
export function createPreToolUseScreening(preToolUse, input, hookSeatMs, notifier) {
|
|
257
|
-
if (preToolUse === undefined)
|
|
258
|
-
return undefined;
|
|
259
|
-
const { toolCallId, toolName } = input.event;
|
|
260
|
-
const screenedName = wireOf("gate.preToolUse", input.event);
|
|
261
|
-
const hookCtx = (seatSignal) => ({
|
|
262
|
-
toolCallId,
|
|
263
|
-
toolName: screenedName,
|
|
264
|
-
...(seatSignal !== undefined ? { signal: seatSignal } : {}),
|
|
265
|
-
...(() => {
|
|
266
|
-
const c = input.trackedCwd?.();
|
|
267
|
-
return typeof c === "string" ? { cwd: c } : {};
|
|
268
|
-
})(),
|
|
269
|
-
...(input.hookEnv !== undefined ? { env: input.hookEnv } : {}),
|
|
270
|
-
...(input.identity !== undefined ? { identity: input.identity } : {}),
|
|
271
|
-
});
|
|
272
|
-
const bound = { timeoutMs: hookSeatMs, ...(input.abortSignal !== undefined ? { signal: input.abortSignal } : {}), abortEnds: true };
|
|
273
|
-
return {
|
|
274
|
-
screen: (args) => runHookSeat("preToolUse", bound, (sig) => preToolUse(screenedName, args, hookCtx(sig))),
|
|
275
|
-
screened: screenPreToolUseResult,
|
|
276
|
-
crashReason: preToolUseCrashReason,
|
|
277
|
-
unansweredReason: async (subject, cause) => {
|
|
278
|
-
if (cause === "timeout")
|
|
279
|
-
traceHookCrash(input, hookSeatExpiredError("preToolUse", hookSeatMs, cause, `${subject} was NOT executed (fail-closed) and the screening face was signalled to stop`), notifier);
|
|
280
|
-
return preToolUseUnansweredReason(subject, hookSeatMs, cause);
|
|
281
|
-
},
|
|
282
|
-
deniedReason: (answer) => decisionText(answer) ?? `tool "${toolName}" blocked by a PreToolUse hook`,
|
|
283
|
-
refusedReason: (answer) => String(answer.message ?? `the PreToolUse hook's result for "${toolName}" was refused by the engine`),
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
208
|
export async function runToolGate(input) {
|
|
287
|
-
const { event,
|
|
209
|
+
const { event, adjudicate, resolveAsk, suspendAsk } = input;
|
|
288
210
|
const { toolCallId, toolName } = event;
|
|
289
211
|
const callSignal = input.callSignal;
|
|
290
212
|
const modelInput = event.input;
|
|
213
|
+
const owned = ownArgs(modelInput);
|
|
214
|
+
const args = owned.ok ? owned.value : modelInput;
|
|
291
215
|
const notifier = createSafeNotifier(input.onNotifyError !== undefined ? { onError: input.onNotifyError } : undefined);
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
await notifier.notifyAsync(async () => {
|
|
298
|
-
const seat = await runHookSeat("permissionDenied", observerBound, (sig) => input.permissionDenied?.({ ...payload, signal: sig }));
|
|
299
|
-
if (seat.expired)
|
|
300
|
-
throw hookSeatExpiredError("permissionDenied", hookSeatMs, seat.cause, "the deny observation was abandoned; the deny itself is unchanged");
|
|
301
|
-
}, "toolGate.permissionDenied");
|
|
216
|
+
const notifyPermissionDeniedSeat = (payload) => {
|
|
217
|
+
const mode = input.observedPermissionMode?.();
|
|
218
|
+
const seen = mode !== undefined ? { ...payload, permissionMode: mode } : payload;
|
|
219
|
+
const onHostObserverFailure = (err) => void notifier.notify(() => { throw err; }, "toolGate.permissionDenied");
|
|
220
|
+
return observePermissionDenied({ legBus: input.modBus, hostObserver: input.permissionDenied, payload: seen, signal: input.abortSignal, onHostObserverFailure });
|
|
302
221
|
};
|
|
303
|
-
const screening = createPreToolUseScreening(
|
|
222
|
+
const screening = createPreToolUseScreening(input);
|
|
304
223
|
const pass = {
|
|
305
224
|
input,
|
|
306
225
|
event,
|
|
@@ -315,8 +234,8 @@ export async function runToolGate(input) {
|
|
|
315
234
|
notifyPermissionDenied: notifyPermissionDeniedSeat,
|
|
316
235
|
screening,
|
|
317
236
|
afterFold: runGateLanes,
|
|
318
|
-
currentInput:
|
|
319
|
-
req: { toolName, args
|
|
237
|
+
currentInput: args,
|
|
238
|
+
req: Object.freeze({ toolName, args, toolCallId, ...(() => { const f = input.toolFaceOf?.(toolName); return f !== undefined ? { face: f } : {}; })() }),
|
|
320
239
|
preToolContext: [],
|
|
321
240
|
hookAsk: undefined,
|
|
322
241
|
parkFailed: undefined,
|
|
@@ -326,29 +245,15 @@ export async function runToolGate(input) {
|
|
|
326
245
|
tightenedBy: undefined,
|
|
327
246
|
policyRewrite: undefined,
|
|
328
247
|
};
|
|
248
|
+
if (!owned.ok)
|
|
249
|
+
return await unownedArgsExit(pass, owned.reason);
|
|
329
250
|
if (screening !== undefined) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const seat = await screening.screen(pass.currentInput);
|
|
334
|
-
if (seat.expired)
|
|
335
|
-
unanswered = seat.cause;
|
|
336
|
-
else
|
|
337
|
-
r = screening.screened(seat.value);
|
|
338
|
-
}
|
|
339
|
-
catch (err) {
|
|
340
|
-
const reason = screening.crashReason(`this call to "${toolName}"`, err);
|
|
341
|
-
traceHookCrash(input, err, notifier);
|
|
342
|
-
return await engineFailClosedExit(pass, reason);
|
|
343
|
-
}
|
|
344
|
-
if (unanswered !== undefined) {
|
|
345
|
-
const reason = await screening.unansweredReason(`this call to "${toolName}"`, unanswered);
|
|
346
|
-
return await engineFailClosedExit(pass, reason);
|
|
251
|
+
const screened = await screening.screen(pass.currentInput, `this call to "${toolName}"`);
|
|
252
|
+
if (screened.kind === "refused") {
|
|
253
|
+
return await engineFailClosedExit(pass, screened.reason);
|
|
347
254
|
}
|
|
255
|
+
const r = screened.answer;
|
|
348
256
|
if (r) {
|
|
349
|
-
if (isEngineRefusal(r)) {
|
|
350
|
-
return await engineFailClosedExit(pass, screening.refusedReason(r));
|
|
351
|
-
}
|
|
352
257
|
if (r.additionalContext) {
|
|
353
258
|
pass.preToolContext.push(r.additionalContext);
|
|
354
259
|
}
|
|
@@ -362,7 +267,7 @@ export async function runToolGate(input) {
|
|
|
362
267
|
pass.hookAsk = r;
|
|
363
268
|
}
|
|
364
269
|
if (r.action === "allow")
|
|
365
|
-
pass.
|
|
270
|
+
pass.hookAllowedBy = screened.answeredBy !== undefined ? [screened.answeredBy] : [];
|
|
366
271
|
}
|
|
367
272
|
}
|
|
368
273
|
return await runGateFold(pass);
|
|
@@ -24,9 +24,27 @@
|
|
|
24
24
|
* before the frame and the transcript read them. A block whose bytes the admission refuses becomes a text
|
|
25
25
|
* block that names the tool, the refusal and the size — never the bytes, and never silently nothing.
|
|
26
26
|
*/
|
|
27
|
-
import type { DocumentContent, ImageContent } from "
|
|
28
|
-
import { type ImageDimensions, type ImageDownsampler } from "
|
|
29
|
-
import { type MediaBlock } from "
|
|
27
|
+
import type { DocumentContent, ImageContent } from "../internal/llm.js";
|
|
28
|
+
import { type ImageDimensions, type ImageDownsampler } from "./image-downsample.js";
|
|
29
|
+
import { type MediaBlock } from "./media-byte-cap.js";
|
|
30
|
+
/** Byte cap on a Read-image WITHOUT a downsampler: an image file is returned AS a visual
|
|
31
|
+
* `ImageContent` block (base64) rather than refused. Bounded so a huge image cannot blow the request.
|
|
32
|
+
* This stat-time cap only bounds the READ; the accept/refuse decision is the base64 gate below (the
|
|
33
|
+
* provider limit is on base64 LENGTH, so the effective no-sharp accept bound is raw ≤ 3.75MB). */
|
|
34
|
+
export declare const MAX_IMAGE_READ_BYTES: number;
|
|
35
|
+
/** Byte cap on a Read-image WITH a downsampler: sharp can shrink a big photo to CC's 2000×2000/3.75MB
|
|
36
|
+
* target, so the smaller hard refusal does not apply (CC readImageWithTokenBudget reads the file
|
|
37
|
+
* unbounded; we keep an OOM sanity bound — deliberate delta, camera photos fit comfortably). */
|
|
38
|
+
export declare const MAX_IMAGE_DOWNSAMPLE_INPUT_BYTES: number;
|
|
39
|
+
/** Max raw size sent whole as a document block (CC `PDF_TARGET_RAW_SIZE`). */
|
|
40
|
+
export declare const PDF_TARGET_RAW_SIZE: number;
|
|
41
|
+
/** Verify the raw bytes actually ARE the image format the extension claims (magic-number sniff). Extension alone
|
|
42
|
+
* is forgeable: a `.png` holding text / an empty file / a truncated blob would otherwise become a malformed
|
|
43
|
+
* `ImageContent` that makes the NEXT provider request fail (400). Pure — no I/O. */
|
|
44
|
+
export declare function imageMagicMatches(bytes: Uint8Array, mimeType: string): boolean;
|
|
45
|
+
/** True when the bytes start with the `%PDF-` magic. Magic outranks extension both ways: a mis-named
|
|
46
|
+
* `.pdf` without it is refused, and a non-`.pdf` file carrying it is read AS a PDF. */
|
|
47
|
+
export declare function pdfMagicMatches(bytes: Uint8Array): boolean;
|
|
30
48
|
/** The image types the content API accepts — the only ones a signature check can verify. */
|
|
31
49
|
export declare const ADMITTED_IMAGE_MIME_TYPES: readonly ["image/png", "image/jpeg", "image/gif", "image/webp"];
|
|
32
50
|
/** The raw-byte read cap for an image, with or without a downsampler. */
|
|
@@ -1,9 +1,27 @@
|
|
|
1
|
-
import { MCP_IMAGE_MAX_BASE64 } from "
|
|
2
|
-
import { claimedMediaType } from "
|
|
3
|
-
import { readMember } from "
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { MCP_IMAGE_MAX_BASE64 } from "./image-downsample.js";
|
|
2
|
+
import { claimedMediaType } from "./media-byte-cap.js";
|
|
3
|
+
import { readMember } from "./thrown-value.js";
|
|
4
|
+
export const MAX_IMAGE_READ_BYTES = 5 * 1024 * 1024;
|
|
5
|
+
export const MAX_IMAGE_DOWNSAMPLE_INPUT_BYTES = 64 * 1024 * 1024;
|
|
6
|
+
export const PDF_TARGET_RAW_SIZE = 20 * 1024 * 1024;
|
|
7
|
+
export function imageMagicMatches(bytes, mimeType) {
|
|
8
|
+
const b = bytes;
|
|
9
|
+
switch (mimeType) {
|
|
10
|
+
case "image/png":
|
|
11
|
+
return b.length >= 8 && b[0] === 0x89 && b[1] === 0x50 && b[2] === 0x4e && b[3] === 0x47 && b[4] === 0x0d && b[5] === 0x0a && b[6] === 0x1a && b[7] === 0x0a;
|
|
12
|
+
case "image/jpeg":
|
|
13
|
+
return b.length >= 3 && b[0] === 0xff && b[1] === 0xd8 && b[2] === 0xff;
|
|
14
|
+
case "image/gif":
|
|
15
|
+
return b.length >= 6 && b[0] === 0x47 && b[1] === 0x49 && b[2] === 0x46 && b[3] === 0x38 && (b[4] === 0x37 || b[4] === 0x39) && b[5] === 0x61;
|
|
16
|
+
case "image/webp":
|
|
17
|
+
return b.length >= 12 && b[0] === 0x52 && b[1] === 0x49 && b[2] === 0x46 && b[3] === 0x46 && b[8] === 0x57 && b[9] === 0x45 && b[10] === 0x42 && b[11] === 0x50;
|
|
18
|
+
default:
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function pdfMagicMatches(bytes) {
|
|
23
|
+
return bytes.length >= 5 && bytes[0] === 0x25 && bytes[1] === 0x50 && bytes[2] === 0x44 && bytes[3] === 0x46 && bytes[4] === 0x2d;
|
|
24
|
+
}
|
|
7
25
|
export const ADMITTED_IMAGE_MIME_TYPES = Object.freeze(["image/png", "image/jpeg", "image/gif", "image/webp"]);
|
|
8
26
|
export function imageReadCap(downsampler) {
|
|
9
27
|
return downsampler ? MAX_IMAGE_DOWNSAMPLE_INPUT_BYTES : MAX_IMAGE_READ_BYTES;
|
|
@@ -56,8 +56,11 @@ export declare class McpConnectionPool {
|
|
|
56
56
|
* transport object that answers differently to two readers cannot split the dial from its key); every other transport member is read here.
|
|
57
57
|
* The declaration's mount identity (`fingerprint`) is part of the key when declared: the revocation probe is asked with it, so two mounts the
|
|
58
58
|
* host tells apart never share one connection (an undeclared fingerprint leaves the key as it always was).
|
|
59
|
+
* So is the startup bound the dial runs under (`startupMs`, the dial's one reading of {@link mcpStartupTimeoutMs}, threaded like `kind`):
|
|
60
|
+
* a connection is dialled under the declaration of the mount that dials it, so a mount never waits on, or shares, a dial bounded by
|
|
61
|
+
* another mount's clock. No bound in force (none declared, no environment seat) leaves the key as it always was.
|
|
59
62
|
*/
|
|
60
|
-
static keyOf(spec: McpServerSpec, principal: string | undefined, kind: string | undefined): string;
|
|
63
|
+
static keyOf(spec: McpServerSpec, principal: string | undefined, kind: string | undefined, startupMs: number | undefined): string;
|
|
61
64
|
/**
|
|
62
65
|
* Lease the connection for `key`, dialling it with `dial` when none is live. `fresh` replaces the pool's current connection with a new
|
|
63
66
|
* dial (a re-dial): the connection it replaces lives on until its other holders release it. Resolves `undefined` once the pool is
|
|
@@ -4,10 +4,15 @@ export class McpConnectionPool {
|
|
|
4
4
|
dialing = new Map();
|
|
5
5
|
generation = new Map();
|
|
6
6
|
shut = false;
|
|
7
|
-
static keyOf(spec, principal, kind) {
|
|
7
|
+
static keyOf(spec, principal, kind, startupMs) {
|
|
8
8
|
const rest = Object.fromEntries(Object.keys(spec.transport).filter((k) => k !== "kind").map((k) => [k, Reflect.get(spec.transport, k)]));
|
|
9
9
|
const fingerprint = spec.fingerprint;
|
|
10
|
-
|
|
10
|
+
const identity = [spec.name, kind ?? null, rest, principal ?? null];
|
|
11
|
+
if (fingerprint !== undefined)
|
|
12
|
+
identity.push(fingerprint);
|
|
13
|
+
if (startupMs !== undefined)
|
|
14
|
+
identity.push({ startupTimeoutMs: startupMs });
|
|
15
|
+
return canonicalize(identity);
|
|
11
16
|
}
|
|
12
17
|
async acquire(key, dial, opts) {
|
|
13
18
|
if (this.shut)
|
package/dist/core/mcp-probe.d.ts
CHANGED
|
@@ -38,15 +38,17 @@ export interface McpProbeOptions {
|
|
|
38
38
|
* on a real leg — so a server that applies per-user rules answers the probe as it would answer the
|
|
39
39
|
* task. */
|
|
40
40
|
principal?: string;
|
|
41
|
-
/**
|
|
42
|
-
* every env-supplied MCP bound keeps, because a larger delay is silently rewritten to 1 ms).
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
41
|
+
/** An OVERALL ceiling on the VERDICT for each server, in whole milliseconds within `[1, MCP_ENV_MS_MAX]` (the
|
|
42
|
+
* ceiling every env-supplied MCP bound keeps, because a larger delay is silently rewritten to 1 ms). The
|
|
43
|
+
* caller's own choice, and it lives BESIDE the per-phase startup bounds the dial runs under — whichever
|
|
44
|
+
* arrives first decides. When it elapses, THAT server's row reads `failed` with `errorCode: "timeout"` and
|
|
45
|
+
* the walk moves on; nothing throws. It does NOT end the dial — nothing here can — so the transport stays
|
|
46
|
+
* open until the dial lands on its own; see the residue note on {@link probeMcpServers}.
|
|
46
47
|
*
|
|
47
|
-
* Default:
|
|
48
|
-
*
|
|
49
|
-
*
|
|
48
|
+
* Default: none. The probe has no clock of its own: it dials through the entrance a task does, so each
|
|
49
|
+
* startup phase (the handshake, then the initial listing) carries that server's own bound from the one
|
|
50
|
+
* reader ({@link import("./mcp.js").mcpStartupTimeoutMs}: its `startupTimeoutMs`, else env `MCP_TIMEOUT`, else
|
|
51
|
+
* the SDK's 60 000 ms) — exactly what a task allows it. */
|
|
50
52
|
timeoutMs?: number;
|
|
51
53
|
/** Abort the whole probe. The call rejects with the signal's own reason (a bare `abort()` gives an
|
|
52
54
|
* `AbortError`) AFTER every server it had opened is closed — see the residue contract on
|
|
@@ -102,7 +104,8 @@ export interface McpProbeOptions {
|
|
|
102
104
|
* return, and NOT that the call itself is bounded. What bounds it, stated part by part rather than
|
|
103
105
|
* summarised into a number that would be wrong:
|
|
104
106
|
* · a dial has two REQUEST-BUDGET phases, each carrying the startup-phase bound ({@link
|
|
105
|
-
* mcpStartupTimeoutMs}
|
|
107
|
+
* import("./mcp.js").mcpStartupTimeoutMs}: the server's own `startupTimeoutMs`, else env `MCP_TIMEOUT`, else the SDK's
|
|
108
|
+
* 60 000 ms default): the handshake, one
|
|
106
109
|
* request; and the initial tool listing, a PAGINATED WALK whose whole budget is that same number
|
|
107
110
|
* (however many pages it takes — and no request at all when the peer advertises no tools). Two
|
|
108
111
|
* budgets, so twice that, not once;
|
package/dist/core/mcp-probe.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
2
2
|
import { snapshotMcpEntries } from "./locked-config.js";
|
|
3
3
|
import { classifyMcpFailure, livenessOf } from "./mcp-failure.js";
|
|
4
|
-
import { MCP_ENV_MS_MAX, materializeMcpTools
|
|
4
|
+
import { MCP_ENV_MS_MAX, materializeMcpTools } from "./mcp.js";
|
|
5
5
|
import { findNamespacePrefixCollision } from "./protocol-naming.js";
|
|
6
6
|
import { MCP_NAMESPACE } from "./protocol-table.js";
|
|
7
7
|
import { mcpManifestEntries } from "./runner/prepare-wiring-manifest.js";
|
|
@@ -62,7 +62,7 @@ function stoppedWaitingStatus(entry, ms) {
|
|
|
62
62
|
}
|
|
63
63
|
export async function probeMcpServers(specs, opts = {}) {
|
|
64
64
|
const declared = snapshotMcpEntries(specs);
|
|
65
|
-
const timeoutMs = wholeInRange("timeoutMs", opts.timeoutMs, 1, MCP_ENV_MS_MAX)
|
|
65
|
+
const timeoutMs = wholeInRange("timeoutMs", opts.timeoutMs, 1, MCP_ENV_MS_MAX);
|
|
66
66
|
const concurrency = wholeInRange("concurrency", opts.concurrency, 1, Number.MAX_SAFE_INTEGER) ?? 1;
|
|
67
67
|
const onElicit = opts.onElicit ?? DECLINE_EVERY_ELICITATION;
|
|
68
68
|
const signal = opts.signal;
|
|
@@ -148,6 +148,22 @@ export interface McpServerSpec {
|
|
|
148
148
|
* (`config.mcp_fingerprint_invalid`).
|
|
149
149
|
*/
|
|
150
150
|
fingerprint?: string;
|
|
151
|
+
/**
|
|
152
|
+
* THIS server's startup bound, in whole milliseconds: the handshake (connect + initialize) and the initial tool listing each carry it
|
|
153
|
+
* (the listing as one walk, however many pages). One knob, three seats, read by one function in this order — this member, else the
|
|
154
|
+
* process-level `MCP_TIMEOUT`, else the MCP SDK's own 60 000 ms — so a server that hangs at startup is cut on its own clock while its
|
|
155
|
+
* siblings keep the deployment's. It bounds only that startup phase: a call's own timeout (`MCP_TOOL_TIMEOUT`) is untouched.
|
|
156
|
+
*
|
|
157
|
+
* The range is the one every MCP millisecond bound keeps, 1 000 to 2 147 483 647 (a larger delay is silently rewritten to 1 ms by the
|
|
158
|
+
* timer, a smaller one is a unit slip). Unlike the environment seat — a string a process may clamp and announce — a declaration is typed
|
|
159
|
+
* data, so anything else (a string, a fraction, zero, a negative, NaN, `null`, a number outside the range) refuses THIS server at its
|
|
160
|
+
* dial (`config.mcp_startup_timeout_invalid`; siblings mount) rather than being clamped or read as the default.
|
|
161
|
+
*
|
|
162
|
+
* The bound a dial runs under (this member, else the environment seat) is part of a pooled connection's identity: mounts under one
|
|
163
|
+
* bound lease ONE connection, mounts under different bounds dial their own — so a mount is never held by another mount's clock.
|
|
164
|
+
* The no-run probe has no clock of its own: each startup phase carries this same bound (a caller's `timeoutMs` is an overall ceiling beside it).
|
|
165
|
+
*/
|
|
166
|
+
startupTimeoutMs?: number;
|
|
151
167
|
}
|
|
152
168
|
type ToolAxes = NonNullable<McpServerSpec["toolAxes"]>;
|
|
153
169
|
/**
|
package/dist/core/mcp.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type McpInstructionsEntry, type
|
|
1
|
+
import { type McpInstructionsEntry, type PromptSectionDisposer } from "./prompt-section-seat.js";
|
|
2
2
|
import { McpConnectionPool } from "./mcp-connection-pool.js";
|
|
3
3
|
import { type McpDelivered, type McpFailureKind, type McpServerLiveness } from "./mcp-failure.js";
|
|
4
4
|
import type { AgentTool } from "../internal/harness-types.js";
|
|
@@ -101,7 +101,7 @@ export interface MaterializedMcp {
|
|
|
101
101
|
toolAxes: McpToolAxis[];
|
|
102
102
|
/**
|
|
103
103
|
* MCP server `instructions` (design/64 §17.3, CC `# MCP Server Instructions`): the optional guidance a
|
|
104
|
-
* connected server returns from `initialize`, after the host's disposition (`
|
|
104
|
+
* connected server returns from `initialize`, after the host's disposition (the `prompt.section` station,
|
|
105
105
|
* applied once at the dial: a dropped entry is absent, a replaced one carries `author: "host"`). The
|
|
106
106
|
* Runner injects these into the (stable) system prompt. One entry per server whose entry survived.
|
|
107
107
|
*/
|
|
@@ -443,11 +443,15 @@ export declare const MCP_IDLE_TIMEOUT_HTTP_DEFAULT_MS: number;
|
|
|
443
443
|
* `MCP_IDLE_TIMEOUT_HTTP`, else the CC-matched default). Exported for tests. */
|
|
444
444
|
export declare function mcpIdleTimeoutMs(kind: "stdio" | "http"): number;
|
|
445
445
|
/**
|
|
446
|
-
* Startup-phase (connect + initial listTools) timeout override in ms
|
|
447
|
-
*
|
|
448
|
-
*
|
|
446
|
+
* Startup-phase (connect + initial listTools) timeout override in ms; undefined keeps the SDK default. Startup
|
|
447
|
+
* deliberately stays bounded: a hung server at materialize time should fail open into a skipped-server warning
|
|
448
|
+
* quickly, not stall task preparation indefinitely. THE one reader of the knob: with a `server`, that
|
|
449
|
+
* declaration's own `startupTimeoutMs` wins over env `MCP_TIMEOUT` (typed data held to the env knob's range
|
|
450
|
+
* [{@link MCP_ENV_MS_MIN}, {@link MCP_ENV_MS_MAX}], but REFUSED outside it — `config.mcp_startup_timeout_invalid`
|
|
451
|
+
* — where a process string is clamped and announced); without one, the process-level bound alone. The env value
|
|
452
|
+
* is resolved either way, so a bad one is announced even when a declaration shadows it.
|
|
449
453
|
*/
|
|
450
|
-
export declare function mcpStartupTimeoutMs(): number | undefined;
|
|
454
|
+
export declare function mcpStartupTimeoutMs(server?: Pick<McpServerSpec, "name" | "startupTimeoutMs">): number | undefined;
|
|
451
455
|
/** The protocol-range condition name for a JSON-RPC error code, or `undefined` for every other code
|
|
452
456
|
* (see {@link MCP_SPEC_ERROR_CODE_NAMES}). */
|
|
453
457
|
export declare function describeMcpSpecErrorCode(code: unknown): string | undefined;
|
|
@@ -605,7 +609,7 @@ reminderDisclosure?: {
|
|
|
605
609
|
}, poolOpts?: {
|
|
606
610
|
pool: McpConnectionPool;
|
|
607
611
|
ownsPool?: boolean;
|
|
608
|
-
}, promptSections?:
|
|
612
|
+
}, promptSections?: PromptSectionDisposer): Promise<MaterializedMcp>;
|
|
609
613
|
/**
|
|
610
614
|
* Fold the caller's AUTHORITATIVE per-tool override (design F: caller = trust root) over the server-hint axis.
|
|
611
615
|
* Unlike server hints, the caller may RAISE or LOWER any axis: `effect` sets the repeat-safety class (lower to
|